Lesen von Antwortheadern mit der Fetch-API

71

Ich bin in einer Google Chrome-Erweiterung mit Berechtigungen für "*://*/*"und versuche, von XMLHttpRequest zur Fetch-API zu wechseln .

Die Erweiterung speichert Anmeldedaten für Benutzereingaben, die früher direkt in den open () -Aufruf des XHR für HTTP Auth eingefügt wurden, aber unter Fetch nicht mehr direkt als Parameter verwendet werden können. Bei HTTP Basic Auth ist das Umgehen dieser Einschränkung trivial, da Sie einen Autorisierungsheader manuell festlegen können:

fetch(url, {
  headers: new Headers({ 'Authorization': 'Basic ' + btoa(login + ':' + pass) })
  } });

HTTP Digest Auth erfordert jedoch mehr Interaktivität. Sie müssen die Parameter lesen, die der Server Ihnen mit seiner 401-Antwort sendet, um ein gültiges Autorisierungstoken zu erstellen. Ich habe versucht, das WWW-AuthenticateAntwortheaderfeld mit diesem Snippet zu lesen :

fetch(url).then(function(resp) {
  resp.headers.forEach(function(val, key) { console.log(key + ' -> ' + val); });
}

Aber alles was ich bekomme ist diese Ausgabe:

content-type -> text/html; charset=iso-8859-1

Was an sich richtig ist, aber laut Chrome's Developer Tools fehlen noch 6 weitere Felder. Wenn ich resp.headers.get("WWW-Authenticate")(oder eines der anderen Felder für diese Angelegenheit) benutze , bekomme ich nur null.

Gibt es eine Chance, mit der Fetch-API zu diesen anderen Feldern zu gelangen?

Jules
quelle

Antworten:

100

Es gibt eine Einschränkung für den Zugriff auf Antwortheader, wenn Sie die Fetch-API über CORS verwenden. Aufgrund dieser Einschränkung können Sie nur auf folgende Standardheader zugreifen:

  • Cache-Control
  • Content-Language
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

Wenn Sie Code für die Google Chrome-Erweiterung schreiben, verwenden Sie CORS . Daher können Sie nicht auf alle Header zugreifen. Wenn Sie den Server steuern, können Sie bodyanstelle von benutzerdefinierte Informationen in der Antwort zurückgebenheaders

Weitere Informationen zu dieser Einschränkung - https://developers.google.com/web/updates/2015/03/introduction-to-fetch#response_types

Rajbir Jawanda
quelle
22
@jules Diese Einschränkung für CORS berücksichtigt die Werte in access-control-expose-headers- oder möglicherweise access-control-allow-headers(wir setzen sie in beide ein).
Jacob
14
access-control-expose-headershat für mich für vom Server zurückgegebene Header gearbeitet - dann sind Header über das Objekt "Header abrufen" verfügbar. Und access-control-allow-headerswurde verwendet , um Anfrage - Header auf dem Server zu ermöglichen (oder ich würde eine Fehlermeldung vom Server beziehen )
Probe
10
Es ist irgendwie dumm, dass dies mit Fetch nicht möglich ist, aber mit XmlHttpRequest gemacht werden kann. Was ist der Sicherheitsvorteil, wenn eine Problemumgehung noch möglich ist?
Sepas
2
@sebas Es sieht so aus, als ob Chrome (und wahrscheinlich auch andere Browser) die gleiche Einschränkung auferlegen XmlHttpRequest.
Benjineer
7
Festlegen, Access-Control-Allow-Headerswann Header vom Client an den Server übergeben werden dürfen (z If-Match. B. ). Festlegen, Access-Control-Expose-Headerswann Header vom Server an den Client zurückgegeben werden dürfen (z ETag. B. ).
Dave Stevens
27

Wenn es NICHT CORS ist:

Beim Abrufen werden beim Debuggen oder wenn Sie console.logantworten, keine Header angezeigt .

Sie müssen die folgende Methode verwenden, um auf Header zuzugreifen.

response.headers.get('x-auth-token')
Nitin Jadhav
quelle
13

Von MDN

Sie können auch alle Header abrufen, indem Sie auf die Einträge Iterator zugreifen.

// Display the key/value pairs
for (var pair of res.headers.entries()) {
   console.log(pair[0]+ ': '+ pair[1]);
}

Beachten Sie auch diesen Teil:

Aus Sicherheitsgründen können einige Header nur vom Benutzeragenten gesteuert werden. Diese Header enthalten die verbotenen Headernamen und die verbotenen Antwortheadernamen.

Avram Tudor
quelle
2
Wenn Sie den Iterator verwenden, wird dieselbe Ausgabe angezeigt. nur das Feld für den Inhaltstyp. und die Listen der verbotenen Headernamen scheinen nur für Änderungen zu gelten und WWW-Authenticatesind auch nicht aufgeführt.
Jules
9

Für die Abwärtskompatibilität mit Browsern, die keine ES2015-Iteratoren unterstützen (und wahrscheinlich auch Polyfills zum Abrufen / Versprechen benötigen), ist die Funktion Headers.forEach die beste Option:

r.headers.forEach(function(value, name) {
    console.log(name + ": " + value);
});

Getestet in IE11 mit Bluebird als Promise Polyfill und whatwg-fetch als Fetch Polyfill. Headers.entries (), Headers.keys () und Headers.values ​​() funktionieren nicht.

Jørn Andre Sundt
quelle
2

Um dieses Problem mit den Einschränkungen zu beheben, ist es gut genug, exponierte Headernamen hinzuzufügen.

Access-Control-Expose-Header: Headername1, Headername2, ...

Nach dem Setzen dieses Headers kann das clientseitige Skript diese Header (Headername1, Headername2, ...) aus der Antwort lesen.

Sheng
quelle
0

Denken Sie auch daran müssen Sie die Antwort auf nächstes passieren .then()nach , res.headers.get()wenn Sie es analysieren. Das vergesse ich immer wieder ...

var link
const loop = () => {
  fetch(options)
    .then(res => { 
      link = res.headers.get('link')
      return res.json()
    })
    .then(body => {
      for (let e of body.stuff) console.log(e)
      if (link) setTimeout(loop, 100)
    })
    .catch(e => {
      throw Error(e)
    })
}
loop()
wbelk
quelle