Антипаттерн: неправильный доступ к многозначным 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>
    

Дальнейшее чтение