适用于:所有 API 管理层级
Azure API 管理通过提供 ProxyError
对象,允许发布服务器响应在处理请求的过程中可能发生的错误情况。 ProxyError
对象可通过 context.LastError 属性访问,并可由 on-error
策略节中的策略使用。 本文提供的参考针对 Azure API 管理中的错误处理功能。
API 管理中的错误处理
Azure API 管理中的策略分为 inbound
、backend
、outbound
和 on-error
部分,如以下示例所示。
<policies>
<inbound>
<!-- statements to be applied to the request go here -->
</inbound>
<backend>
<!-- statements to be applied before the request is
forwarded to the backend service go here -->
</backend>
<outbound>
<!-- statements to be applied to the response go here -->
</outbound>
<on-error>
<!-- statements to be applied if there is an error
condition go here -->
</on-error>
</policies>
在处理请求期间,内置的步骤与请求范围内的策略一起执行。 如果发生错误,处理会立即跳转到 on-error
策略节。
on-error
策略节可以在任何范围内使用。 API 发布者可配置自定义行为,例如将错误记录到 Event Hubs,或者创建新的响应返回给调用方。
注释
默认情况下,on-error
节不存在于策略中。 要将 on-error
节添加到策略,请在策略编辑器中浏览到所需策略,然后将其添加进去。 有关配置策略的详细信息,请参阅 API 管理中的策略。
如果没有 on-error
节,则在出现错误情况时,调用方会收到 400 或 500 HTTP 响应消息。
出错时允许的策略
以下策略可以用在 on-error
策略节中。
- choose
- 设置变量
- 查找和替换
- return-response
- 设置标题
- 设置方法
- set-status
- send-request
- 发送单向请求
- log-to-eventhub
- json-to-xml
- xml-to-json
- limit-concurrency
- mock-response
- 重试
- 跟踪
LastError
当发生错误且控制跳转到 on-error
策略节时,错误会存储在 context.LastError 属性中,该属性可以通过 on-error
节中的策略进行访问。 LastError 具有以下属性。
名称 | 类型 | DESCRIPTION | 必选 |
---|---|---|---|
Source |
字符串 | 命名发生错误的元素。 可以是策略或内置管道步骤名称。 | 是的 |
Reason |
字符串 | 计算机友好错误代码,可以用在错误处理中。 | 否 |
Message |
字符串 | 用户可读的错误说明。 | 是的 |
Scope |
字符串 | 出现错误的范围的名称。 | 否 |
Section |
字符串 | 出错的部分名称。 可能的值:“inbound”、“backend”、“outbound”或“on-error”。 | 否 |
Path |
字符串 | 指定嵌套策略层次结构,例如“choose[3]/when[2]”。 嵌套策略的多个实例从 1 开始索引。 | 否 |
PolicyId |
字符串 | 在其中发生错误的策略的 id 属性(如果已由客户指定)的值 |
否 |
小窍门
可以通过 context.Response.StatusCode 访问状态代码。
注释
所有策略都有一个可选的 id
属性,该属性可以添加到策略的根元素。 如果出现错误情况时该属性存在于策略中,则可使用 context.LastError.PolicyId
属性检索该属性的值。
针对内置步骤的预定义错误
针对评估内置处理步骤期间可能发生的错误情况,预定义了以下错误。
来源 | 条件 | 原因 | 消息 |
---|---|---|---|
配置 | URI 与任何 API 或操作均不匹配 | OperationNotFound | 无法匹配操作的传入请求。 |
authorization | 未提供订阅密钥 | 订阅密钥未找到 | 由于缺少订阅密钥,访问被拒绝。 请确保在向此 API 发出请求时包括订阅密钥。 |
authorization | 订阅密钥值无效 | 订阅密钥无效 | 由于订阅密钥无效,访问被拒绝。 请确保提供活动订阅的有效密钥。 |
多个 | 请求挂起时,客户端中止了下游连接(从客户端到 API 管理网关) | 客户端连接失败 | 多个 |
多个 | 上游连接(从 API 管理网关到后端服务)未建立或已被后端中止 | 后端连接失败 | 多个 |
多个 | 在计算特定表达式期间发生运行时异常 | ExpressionValueEvaluationFailure | 多个 |
针对策略的预定义错误
针对策略评估期间可能发生的错误情况,预定义了以下错误。
来源 | 条件 | 原因 | 消息 |
---|---|---|---|
rate-limit | 已超出速率上限 | RateLimitExceeded | 超出速率限制 |
quota | 超出配额 | QuotaExceeded | 呼叫量配额已用完 配额会在 xx:xx:xx 复原。 -或- 超出带宽配额。 配额会在 xx:xx:xx 复原。 |
jsonp | 回调参数值无效(包含错误字符) | CallbackParameterInvalid | 回调参数 {callback-parameter-name} 的值不是有效的 JavaScript 标识符。 |
IP过滤器 | 无法分析请求中的调用方 IP | FailedToParseCallerIP | 无法确定调用方的 IP 地址。 访问被拒绝。 |
IP过滤器 | 调用方 IP 不在允许列表中 | CallerIpNotAllowed | 不允许调用方 IP 地址 {ip-address}。 访问被拒绝。 |
IP过滤器 | 调用方 IP 位于阻止列表中 | 呼叫者IP被封锁 | 已阻止调用方 IP 地址。 访问被拒绝。 |
check-header | 必需的标头不存在或缺少值 | HeaderNotFound | 在请求中找不到标头 {header-name}。 访问被拒绝。 |
check-header | 必需的标头不存在或缺少值 | HeaderValueNotAllowed | 不允许标头 {header-name} 的值 {header-value}。 访问被拒绝。 |
validate-jwt | 请求中缺少 Jwt 令牌 | TokenNotPresent | JWT 不存在。 |
validate-jwt | 签名验证失败 | TokenSignatureInvalid | <来自 jwt 库的消息>。 访问被拒绝。 |
JWT验证 | 受众无效 | TokenAudienceNotAllowed | <来自 jwt 库的消息>。 访问被拒绝。 |
validate-jwt | 颁发者无效 | TokenIssuerNotAllowed | <来自 jwt 库的消息>。 访问被拒绝。 |
validate-jwt | 令牌已过期 | 令牌已过期 | <来自 jwt 库的消息>。 访问被拒绝。 |
validate-jwt | 按 ID 无法解析签名密钥 | 令牌签名密钥未找到 | <来自 jwt 库的消息>。 访问被拒绝。 |
validate-jwt | 令牌中缺少必需的声明 | TokenClaimNotFound | JWT 令牌缺少以下声明: <c1>、<c2>… 访问被拒绝。 |
validate-jwt | 声明值不匹配 | TokenClaimValueNotAllowed | 不允许声明 {claim-name} 的值 {claim-value}。 访问被拒绝。 |
validate-jwt | 其他验证失败 | JWT无效 | <jwt 库中的消息> |
forward-request 或 send-request | 在配置的超时时间内,未从后端收到 HTTP 响应状态代码和标头 | 超时 | 多个 |
示例:
将 API 策略设置为以下内容:
<policies>
<inbound>
<base />
</inbound>
<backend>
<base />
</backend>
<outbound>
<base />
</outbound>
<on-error>
<set-header name="ErrorSource" exists-action="override">
<value>@(context.LastError.Source)</value>
</set-header>
<set-header name="ErrorReason" exists-action="override">
<value>@(context.LastError.Reason)</value>
</set-header>
<set-header name="ErrorMessage" exists-action="override">
<value>@(context.LastError.Message)</value>
</set-header>
<set-header name="ErrorScope" exists-action="override">
<value>@(context.LastError.Scope)</value>
</set-header>
<set-header name="ErrorSection" exists-action="override">
<value>@(context.LastError.Section)</value>
</set-header>
<set-header name="ErrorPath" exists-action="override">
<value>@(context.LastError.Path)</value>
</set-header>
<set-header name="ErrorPolicyId" exists-action="override">
<value>@(context.LastError.PolicyId)</value>
</set-header>
<set-header name="ErrorStatusCode" exists-action="override">
<value>@(context.Response.StatusCode.ToString())</value>
</set-header>
<base />
</on-error>
</policies>
发送未经授权的请求将导致以下响应:
后续步骤
若要详细了解如何使用策略,请参阅:
- 教程:转换和保护 API
- 策略参考,其中提供了策略语句及其设置的完整列表
- 策略表达式
- 设置或编辑策略
- 策略示例