Czy można dodać nagłówki żądań do żądania iframe src?

83

Rozumiem, że podczas wykonywania wywołań AJAX w JavaScript można bardzo łatwo ustawić nagłówki żądań HTTP.

Czy można jednak ustawić niestandardowe nagłówki żądań HTTP podczas wstawiania elementu iframe do strony za pomocą skryptu?

<iframe src="someURL"> <!-- is there any place to set headers in this? -->
onlywei
źródło

Odpowiedzi:

31

Nie, nie możesz. Możesz jednak ustawić iframeźródło na jakiś rodzaj skryptu wstępnego ładowania, który używa AJAX do pobierania rzeczywistej strony ze wszystkimi żądanymi nagłówkami.

Niet the Dark Absol
źródło
4
Cześć Niet, Czy możesz podać przykładowy kod implementacji w JSFiddle
Naveen Reddy
Myślę, że Niet ma na myśli coś takiego, jak ten stackoverflow.com/a/17695034/1524918
Ryan Kara
5
Czy żądanie w takim skrypcie wstępnego ładowania nie byłoby wysyłane do innej domeny, a tym samym naruszałoby zasady tego samego pochodzenia?
mart1n
Jakie nagłówki są wysyłane domyślnie? Czy jest w tym jakiś standard?
Załóż pozew Moniki z
74

Możesz wysłać żądanie w javascript, ustawiając dowolne nagłówki. Wtedy możesz URL.createObjectURL()zdobyć coś odpowiedniego dla srcelementu iframe.

var xhr = new XMLHttpRequest();

xhr.open('GET', 'page.html');
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 :(');
    }
  }
}

Zachowywany jest typ MIME odpowiedzi. Więc jeśli otrzymasz odpowiedź HTML, kod HTML zostanie wyświetlony w ramce iframe. Jeśli poprosiłeś o plik PDF, przeglądarka PDF w przeglądarce włączy się do elementu iframe.

Jeśli jest to część długotrwałej aplikacji po stronie klienta, możesz chcieć użyć, URL.revokeObjectURL()aby uniknąć wycieków pamięci.

Adresy URL obiektów są również całkiem interesujące. Są w formie blob:https://your.domain/1e8def13-3817-4eab-ad8a-160923995170. W rzeczywistości możesz je otworzyć w nowej karcie i zobaczyć odpowiedź, a zostaną one odrzucone, gdy kontekst, który je utworzył, zostanie zamknięty.

Oto pełny przykład: https://github.com/courajs/pdf-poc

FellowMD
źródło
Doskonały. Działał bez zarzutu. Dziękuję Ci.
mike123
ty co człowieku! Pracuję nad komponentem Angular 5 zainspirowanym tym kodem, aby pokazać podglądy PDF w Angularjs. to bardzo mi pomogło
FireDragon
Dziękuję Ci! Uratowałeś mi życie!
Renato Souza de Oliveira
1
@BSSchwarzkopf wygląda na to, że masz rację. Adresy URL obiektów blob są obsługiwane w Edge, ale nie będą działać w atrybucie src elementu iframe. Uważam, że jest to naruszenie specyfikacji: „Ten schemat powinien być możliwy do użycia z interfejsami API sieci Web… oraz z elementami zaprojektowanymi do używania z adresami URL HTTP… Ogólnie rzecz biorąc, schemat ten powinien być zaprojektowany tak, aby być używane wszędzie tam, gdzie można używać adresów URL w sieci ”. Problem z Edge tracker: developer.microsoft.com/en-us/microsoft-edge/platform/issues/ ... Spec: w3.org/TR/FileAPI/#use-cases-scheme
FellowMD
Otrzymuję komunikat „Nie udało się wykonać polecenia„ createObjectURL ”na„ URL ”: nie znaleziono funkcji pasującej do podanego podpisu." w przeglądarce Chrome 84.0.4147.105.
poiuytrez
3

Okazuje się, że URL.createObjectURL () jest przestarzały w Chrome 71
(patrz https://developers.google.com/web/updates/2018/10/chrome-71-deps-rems )
Opierając się na @Niet the dark Absol i Doskonałe odpowiedzi @ FellowMD, oto jak załadować plik do iframe, jeśli musisz przekazać nagłówki uwierzytelniania. (Nie możesz po prostu ustawić atrybutu src na adres URL):

$scope.load() {
    var iframe = #angular.element("#reportViewer");
    var url = "http://your.url.com/path/etc";
    var token = "your-long-auth-token";
    var headers = [['Authorization', 'Bearer ' + token]];
    $scope.populateIframe(iframe, url, headers);
}

$scope.populateIframe = function (iframe, url, headers) {
    var xhr = new XMLHttpRequest();
    xhr.open('GET', url);
    xhr.onreadystatechange = handler;
    xhr.responseType = 'document';
    headers.forEach(function (header) {
        xhr.setRequestHeader(header[0], header[1]);
    });
    xhr.send();

    function handler() {
        if (this.readyState === this.DONE) {
            if (this.status === 200) {
                var content = iframe[0].contentWindow ||
                    iframe[0].contentDocument.document || 
                    iframe[0].contentDocument;
                content.document.open();
                content.document.write(this.response.documentElement.innerHTML);
                content.document.close();
            } else {
                iframe.attr('srcdoc', '<html><head></head><body>Error loading page.</body></html>');
            }
        }
    }
}

i krzycz do courajs: https://github.com/courajs/pdf-poc/blob/master/script.js

TomEberhard
źródło
1
Z linku Google: „Metoda URL.createObjectURL () została usunięta z interfejsu MediaStream”. Czy to wycofanie, które ma wpływ na interfejs MediaStream, ma znaczenie dla drugiej odpowiedzi? (Myślę, że nie)
Jared Thirsk
Nie wycofano. Usunięto tylko z MediaStream
TheMaster
1
@TheMaster tak właśnie mówi dokumentacja, ale spędziłem kilka godzin próbując go uruchomić i nie udało mi się. Nie może spekulować, dlaczego. Kod pokazany powyżej jest tym, co działało w momencie, gdy go zakodowałem, nie mam przepustowości, aby spróbować ponownie.
TomEberhard
Możesz użyć tej metody z obiektami Blob. W twoim przypadku wyglądałoby to tak, jakURL.createObjectURL(new Blob([this.response.documentElement.innerHTML]))
u.unver34
createObjectURLjest przestarzały tylko dla argumentów MediaStream. Przekazywanie obiektu Blob nie jest przestarzałe i w rzeczywistości powoduje dość szerokie i rosnące użycie . Doceniam jednak wysiłek, aby wszystko było na bieżąco :)
FellowMD
2

Ponieważ odpowiedź @FellowMD nie działa na nowoczesnych przeglądarkach ze względu na deprecjację createObjectURL, zastosowałem to samo podejście, ale używając atrybutu iframe srcDoc.

  1. Pobierz zawartość do wyświetlenia w elemencie iframe przy użyciu XMLHttpRequest lub dowolnej innej metody
  2. Ustaw parametr srcdoc elementu iframe

Poniżej przykład Reacta (wiem, że to przesada):

import React, {useEffect, useState} from 'react';

function App() {
  const [content, setContent] = useState('');


  useEffect(() => {
    // Fetch the content using the method of your choice
    const fetchedContent = '<h1>Some HTML</h1>';
    setContent(fetchedContent);
  }, []);


  return (
    <div className="App">
      <iframe sandbox id="inlineFrameExample"
              title="Inline Frame Example"
              width="300"
              height="200"
              srcDoc={content}>
      </iframe>


    </div>
  );
}

export default App;

Srcdoc jest teraz obsługiwany w większości przeglądarek. Wygląda na to, że Edge trochę spóźnił się z jego wdrożeniem: https://caniuse.com/#feat=iframe-srcdoc

poiuytrez
źródło
createObjectURLjest przestarzały tylko dla argumentów MediaStream. Przekazywanie obiektu Blob nie jest przestarzałe i w rzeczywistości powoduje dość szerokie i rosnące użycie . Doceniam jednak wysiłek, aby wszystko było na bieżąco :)
FellowMD