Антипаттерн: неправильный доступ к многозначным HTTP-заголовкам в прокси-сервере API

Вы просматриваете документацию Apigee Edge .
Перейдите в документацию Apigee
X.info

HTTP-заголовки представляют собой пары «имя-значение», позволяющие клиентским приложениям и серверным службам передавать дополнительную информацию о запросах и ответах соответственно. Вот несколько простых примеров:

  • В заголовке запроса авторизации на сервер передаются учетные данные пользователя:
    Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l
  • Заголовок Content-Type указывает тип содержимого запроса/ответа, отправляемого в ответ:
    Content-Type: application/json

В зависимости от определений полей заголовка, HTTP-заголовки могут содержать одно или несколько значений. Многозначный заголовок будет содержать значения, разделенные запятыми. Вот несколько примеров заголовков, содержащих несколько значений:

  • 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 Edge позволяет разработчикам легко получать доступ к заголовкам, используя переменные потока в любой из политик Edge или условных потоков. Вот список переменных, которые можно использовать для доступа к конкретному заголовку запроса или ответа в Edge:

Переменные потока:

  • 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:

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

Вот пример политики AssignMessage, демонстрирующий, как прочитать значение заголовка запроса и сохранить его в переменную:

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

Антипаттерн

Доступ к значениям HTTP-заголовков в политиках Edge таким образом, чтобы возвращалось только первое значение, является некорректным и может вызвать проблемы, если конкретный HTTP-заголовок (или заголовки) имеет более одного значения.

В следующих разделах приведены примеры доступа к заголовкам.

Пример 1: Чтение многозначного заголовка Accept с помощью кода JavaScript.

Обратите внимание, что заголовок Accept содержит несколько значений, как показано ниже:

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

Вот код JavaScript, который считывает значение из заголовка Accept :

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

Приведённый выше код JavaScript возвращает только первое значение из заголовка Accept , например, text/html .

Пример 2: Чтение многозначного заголовка Access-Control-Allow-Headers в политике AssignMessage или RaiseFault.

Обратите внимание, что заголовок Access-Control-Allow-Headers имеет несколько значений, как показано ниже:

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

Вот фрагмент кода из политики AssignMessage или RaiseFault, устанавливающий заголовок Access-Control-Allow-Headers :

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

Приведённый выше код устанавливает заголовок Access-Control-Allow-Headers используя только первое значение из заголовка запроса Access-Control-Allow-Headers , в данном примере content-type .

Влияние

  1. В обоих приведенных выше примерах обратите внимание, что возвращается только первое значение из многозначных заголовков. Если эти значения впоследствии будут использованы другой политикой в ​​потоке API-прокси или бэкэнд-сервисом для выполнения какой-либо функции или логики, это может привести к неожиданному результату.
  2. Когда значения заголовков запроса передаются на целевой сервер, запросы к API могут обрабатываться бэкэндом некорректно, что может привести к неверным результатам.
  3. Если клиентское приложение зависит от определенных значений заголовков из ответа Edge, то оно также может обрабатывать данные некорректно и выдавать неправильные результаты.

Передовая практика

  1. Используйте соответствующие встроенные переменные потока: request.header. header_name .values.count , request.header. header_name . N response.header. header_name .values.count , response.header. header_name.N .

    Затем выполните итерацию, чтобы получить все значения из определенного заголовка в политиках вызовов JavaScript или Java.

    Пример: образец кода JavaScript для чтения заголовка, содержащего несколько значений.

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

    Например, application/xml;q=0.9, */*;q=0.8 будет отображаться как одно значение с приведенным выше кодом.

    Если значения заголовка необходимо разделить с помощью точки с запятой в качестве разделителя, используйте string.split(";") для разделения их на отдельные значения.

  2. Используйте функцию substring() для переменной потока request.header. header_name .values ​​в политике RaiseFault или AssignMessage, чтобы прочитать все значения определенного заголовка.

    Пример: Пример политики RaiseFault или AssignMessage для чтения заголовка с несколькими значениями.

    <Set>
      <Headers>
       <Header name="Access-Control-Allow-Headers">{substring(request.header.Access-Control-Request-Headers.values,1,-1)}</Header>
      </Headers>
    </Set>

Дополнительная информация