web-dev-qa-db-fra.com

Comment définir des en-têtes http personnalisés lors du changement de iframe src?

Existe-t-il un moyen d'ajouter un en-tête http personnalisé dans la demande effectuée par un <iframe> lors du changement de source (src) en utilisant javascript?

36
dave

Vous pouvez faire en sorte que les résultats d'une demande ajax contenant des en-têtes personnalisés soient définis comme le contenu d'une iframe:

$.ajax({
    type: "GET", 
    url: "https://app.icontact.com/icp/a/",
    contentType: "application/json",
    beforeSend: function(xhr, settings){
            xhr.setRequestHeader("some_custom_header", "foo");},
    success: function(data){
        $("#output_iframe_id").attr('src',"data:text/html;charset=utf-8," + escape(data))
    }
});

Cela suppose que l'iframe pointe vers un src interdomaine. C'est plus simple si tout est sur le même domaine.

Edit: Essayez peut-être cette variante.

$.ajax({
    type: "GET", 
    url: "https://app.icontact.com/icp/a/",
    contentType: "application/json",
    beforeSend: function(xhr, settings){
            xhr.setRequestHeader("some_custom_header", "foo");},
    success: function(data){
        $("#output_iframe_id").attr('src',"/")
        $("#output_iframe_id").contents().find('html').html(data); 
    }
});
31
Matthew Graves

Plutôt que d'utiliser un URI de données ou de définir le contenu sur une chaîne, vous pouvez utiliser URL.createObjectURL() , et le définir comme src de l'iframe.

var xhr = new XMLHttpRequest();

xhr.open('GET', 'some.pdf');
xhr.onreadystatechange = handler;
xhr.responseType = 'blob';
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
xhr.send();

function handler() {
  if (this.readyState === this.DONE) {
    if (this.status === 200) {
      // this.response is a Blob, because we set responseType above
      var data_url = URL.createObjectURL(this.response);
      document.querySelector('#output-frame-id').src = data_url;
    } else {
      console.error('no pdf :(');
    }
  }
}

Les URL des objets sont assez intéressantes. Ils sont de la forme blob:https://your.domain/1e8def13-3817-4eab-ad8a-160923995170. Vous pouvez réellement les ouvrir dans un nouvel onglet et voir la réponse, et ils sont supprimés lorsque le contexte qui les a créés est fermé.

Voici un exemple complet: https://github.com/courajs/pdf-poc

10
FellowMD

Le code suivant fonctionne. Il s'agit d'une modification du code fourni par Matthew Graves , modifié pour utiliser l'attribut srcdoc pour résoudre le problème des références CSS et JavaScript non exécutées. Malheureusement, cela ne fonctionne que dans Chrome.

 $.ajax({
        type: "GET", 
        url: "https://app.icontact.com/icp/a/",
        contentType: "application/json",
        beforeSend: function(xhr, settings){
                xhr.setRequestHeader("some_custom_header", "foo");},
        success: function(data){
            $("#output_iframe_id").attr('srcdoc',data)
        }
    });

Edit : Enfin, j'ai résolu le problème des blocs de scripts cross-browser, en les réaffectant à la fonction iframe on document.ready:

$(document).ready(function () {
    var doc = $(document);
    if (frames.length > 0) {
        doc = frames[0].document;
        $(doc).find('script').each(function () {
            var script = document.createElement("script");
            if ($(this).attr("type") != null) script.type = $(this).attr("type");
            if ($(this).attr("src") != null) script.src = $(this).attr("src");
            script.text = $(this).html();
            $(doc).find('head')[0].appendChild(script);
            $(this).remove();
        });
    }
});
5
dave

J'ai fini par suivre l'approche proposée par les autres réponses ici, qui utilise ajax pour obtenir la chaîne html, puis définit directement le contenu du iFrame.

Cependant, j'ai utilisé l'approche publiée dans ce réponse pour définir le contenu de iFrame, car j'ai trouvé que cela fonctionnait bien sur plusieurs plates-formes avec presque tous les appareils que je pouvais creuser.

Testé - réussi:

  • Chrome 54 (ordinateur de bureau) ^
  • Firefox 49 (bureau) ^
  • IE 11 (bureau) ^
  • IE 10 (bureau) en mode émulation ^
  • Safari/Chrome sur iOS 8 (iPad)
  • Chrome sur Android 6 (téléphone Nexus)
  • Edge sur Lumia 950 (Win 10 Phone)

^ a confirmé que les css et js liés dans le contenu fonctionnent correctement (d'autres non testés)

Testé - échoué:

  • IE 9 (bureau) en mode émulation
  • Safari/Chrome sur iOS 7 (iPhone)

Donc, les assembler donne quelque chose comme ça (Remarque: je n'ai pas réellement exécuté ce code exact):

$.ajax({
    type: "GET", 
    url: "https://yourdomain.com/gethtml",
    beforeSend: function(xhr) {
        xhr.setRequestHeader("yourheader", "value");
    },
    success: function(data) {
        var iframeDoc = document.querySelector('#myiframe').contentWindow.document;
        iframeDoc.open('text/html', 'replace');
        iframeDoc.write(data);
        iframeDoc.close();
    }
});

Voici un exemple de configuration du contenu de iFramedans ce JS Bin

Edit: Voici la partie html

<iframe id="myiframe" src="about:blank"></iframe>

Édition 2:

La solution ci-dessus semble ne plus fonctionner dans Firefox (50.1.0) pour une raison inconnue. En utilisant la solution dans cette réponse J'ai maintenant changé de code pour l'exemple ci-dessous, qui semble également être plus robuste:

$.ajax({
    type: "GET", 
    url: "https://yourdomain.com/gethtml",
    beforeSend: function(xhr) {
        xhr.setRequestHeader("yourheader", "value");
    },
    success: function(data) {
        var iframe = document.getElementById('myiframe');
        iframe.contentWindow.contents = data;
        iframe.src = 'javascript:window["contents"]';
    }
});
5
Jono Job