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

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

Заголовки 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>

Дополнительные материалы