反模式:在 API 代理中错误地访问多值 HTTP 标头

<ph type="x-smartling-placeholder"></ph> 您正在查看 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 中的特定请求或响应标头:

流变量:

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

反模式

以仅返回第一个值的方式在 Edge 政策中访问 HTTP 标头的值 不正确,如果特定 HTTP 标头有多个值,可能会导致问题。

以下部分介绍了标题访问的示例。

示例 1:使用 JavaScript 代码读取多值 Accept 标头

假设 Accept 标头具有多个值,如下所示:

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

以下是从 Accept 标头读取值的 JavaScript 代码:

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

上面的 JavaScript 代码只会返回 Accept 标头中的第一个值,例如 text/html

示例 2:读取 AssignMessage 或 RaiseFault 政策中的多值 Access-Control-Allow-Headers 标头

假设 Access-Control-Allow-Headers 标头具有多个值,如下所示:

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

以下是设置 Access-Control-Allow-Headers 标头的 AssignMessage 或 RaiseFault 政策的部分代码:

<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.countrequest.header.header_name.Nresponse.header.header_name.values.countresponse.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. 在 RaiseFault 或 AssignMessage 政策中的流变量 request.header.header_name.values 上使用 substring() 函数可读取特定标头的所有值。

    示例:读取多值标头的 RaiseFault 或 AssignMessage 政策

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

更多详情