Falscher Zugriff auf HTTP-Header mit mehreren Werten in einem API-Proxy

Sie lesen gerade die Dokumentation zu Apigee und Apigee Hybrid.
Apigee Edge-Dokumentation aufrufen.

Die HTTP-Header sind die Name/Wert-Paare, mit denen Client- und Backend-Dienste zusätzliche Informationen zu Anfragen und Antworten weiterleiten können. Hier einige einfache Beispiele:

  • Der Header der Autorisierungsanfrage sendet die Anmeldedaten an den Server:
    Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
  • Der Header Content-Type gibt den Typ des gesendeten Anfrage-/Antwortinhalts an:
    Content-Type: application/json

Die HTTP-Header können je nach den Headerfelddefinitionen einen oder mehrere Werte haben. Ein Header mit mehreren Werten enthält kommagetrennte Werte. Beispiele für Header mit mehreren Werten:

  • Cache-Control: no-cache, no-store, must-revalidate
  • Accept: text/html, application/xhtml+xml, application/xml;q=0.9, */*;q=0.8
  • X-Forwarded-For: 10.125.5.30, 10.125.9.125

Apigee ermöglicht Entwicklern, über Ablaufvariablen in beliebigen Richtlinien oder bedingten Abläufen auf Header zuzugreifen. Im Folgenden finden Sie die Liste der Variablen, die verwendet werden können, um auf eine bestimmte Anfrage oder einen Antwortheader in Apigee zuzugreifen:

Ablaufvariablen:

  • message.header.header-name
  • request.header.header-name
  • response.header.header-name
  • message.header.header-name.N
  • request.header.header-name.N
  • response.header.header-name.N

JavaScript-Objekte:

  • context.proxyRequest.headers.header-name
  • context.targetRequest.headers.header-name
  • context.proxyResponse.headers.header-name
  • context.targetResponse.headers.header-name

Hier ist ein Beispiel für eine AssignMessage-Richtlinie, die zeigt, wie ein Wert eines Anfrageheaders gelesen und in einer Variablen gespeichert wird:

<AssignMessage continueOnError="false" enabled="true" name="assign-message-default">
  <AssignVariable>
    <Name>reqUserAgent</Name>
    <Ref>request.header.User-Agent</Ref>
  </AssignVariable>
</AssignMessage>

Anti-Pattern

Der Zugriff auf die Werte von HTTP-Headern in Apigee-Richtlinien, sodass nur der erste Wert zurückgegeben wird, ist nicht korrekt und kann zu Problemen führen, wenn der jeweilige HTTP-Header mehrere Werte enthält.

Die folgenden Abschnitte enthalten Beispiele für den Headerzugriff.

Beispiel 1: Header mit mehreren Werten mit JavaScript-Code lesen

Beachten Sie, dass der Header Accept mehrere Werte hat, wie unten gezeigt:

Accept: text/html, application/xhtml+xml, application/xml

Hier ist der JavaScript-Code, mit dem der Wert des Headers Accept gelesen wird:

// Read the values from Accept header
var acceptHeaderValues = context.getVariable("request.header.Accept");

Der obige JavaScript-Code gibt nur den ersten Wert des Headers Accept zurück, z. B. text/html.

Beispiel 2: Mehrwertiger Header "Access-Control-Allow-Headers" in der Richtlinie "AssignedMessage" oder "RaiseFault" lesen

Beachten Sie, dass der Header Access-Control-Allow-Headers mehrere Werte hat, wie unten gezeigt:

Access-Control-Allow-Headers: content-type, authorization

Folgendes ist ein Teil des Codes aus der Richtlinie "AssignMessage" oder "Raisefault" für die Einstellung des Headers Access-Control-Allow-Headers:

<Set>
  <Headers>
    <Header name="Access-Control-Allow-Headers">{request.header.Access-Control-Request-Headers}</Header>
  </Headers>
</Set>

Der obige Code legt den Header Access-Control-Allow-Headers mit dem ersten Wert aus dem Anfrageheader Access-Control-Allow-Headers fest, in diesem Beispiel content-type.

Auswirkungen

  1. Beachten Sie in beiden Beispielen, dass nur der erste Wert von Headern mit mehreren Werten zurückgegeben wird. Wenn diese Werte anschließend von einer anderen Richtlinie im API-Proxy-Ablauf oder vom Back-End-Dienst zum Ausführen einer Funktion oder Logik verwendet werden, kann dies zu einem unerwarteten Ergebnis führen.
  2. Wenn auf die Anfrageheaderwerte zugegriffen wird und diese an den Zielserver gesendet werden, werden API-Anfragen möglicherweise vom Back-End falsch verarbeitet und können daher fehlerhafte Ergebnisse liefern.
  3. Wenn die Clientanwendung von bestimmten Headerwerten aus der Apigee-Antwort abhängig ist, kann sie auch falsch verarbeitet werden und falsche Ergebnisse liefern.

Best Practice

  1. Verweisen Sie auf die request.header.header_name.values.string-Form der Ablaufvariablen, um alle Werte eines bestimmten Headers zu lesen.

    Beispiel: Ein Beispielfragment, das in RaiseFault oder AssignMessage verwendet werden könnte, um einen mehrwertigen Header zu lesen

    <Set>
      <Headers>
        <Header name="Inbound-Headers">{request.header.Accept.values.string}</Header>
      </Headers>
    </Set>
  2. Wenn Sie individuellen Zugriff auf jeden der verschiedenen Werte wünschen, können Sie die jeweilige integrierte Ablaufvariable verwenden: request.header.header_name.values.count ,request.header.header_name.N, response.header.header_name.values.count ,response.header.header_name.N.

    Wiederholen Sie dann den Vorgang, um alle Werte aus einem bestimmten Header in JavaScript- oder Java-Callout-Richtlinien abzurufen.

    Beispiel: JavaScript-Code zum Lesen eines Headers mit mehreren Werten

    for (var i = 1; i <=context.getVariable('request.header.Accept.values.count'); i++)
    {
      print(context.getVariable('request.header.Accept.' + i));
    }

    Beispiel: application/xml;q=0.9, */*;q=0.8 wird mit dem obigen Code als zwei Werte angezeigt. Der erste Wert ist application/xml;q=0.9, der zweite Wert */*;q=0.8.

    Wenn die Headerwerte durch Semikolons getrennt werden müssen, können Sie innerhalb des JavaScript-Callouts string.split(";") verwenden, um die jeweiligen Werte zu trennen.

  3. Alternativ können Sie die substring()-Funktion verwenden, die in einer Nachrichtenvorlage für die Ablaufvariable request.header.header_name.values verfügbar ist, um alle Werte eines bestimmten Headers zu lesen.

    Beispiel: substring() kann in einer Nachrichtenvorlage verwendet werden, um einen vollständigen Header mit mehreren Werten zu lesen

    <Set>
      <Headers>
       <Header name="Inbound-Headers">{substring(request.header.Accept.values,1,-1)}</Header>
      </Headers>
    </Set>

Weitere Informationen