本页面适用于 Apigee 和 Apigee Hybrid。
查看 Apigee Edge 文档。
内容
通过 ExternalCallout 政策,您可以向 gRPC 服务器发送 gRPC 请求,以实现 Apigee 政策不支持的自定义行为。您可以在服务器代码中轻松地访问和修改代理流中的流变量。
Apigee 通过 ExternalCallout 政策使用 API 与 gRPC 服务器通信。 Apigee 使用该 API 向 gRPC 服务器发送流变量。您可以在 gRPC 服务器中读取及修改(具体取决于变量权限)流变量参考页面中列出的流变量以及您在政策 XML 中指定的其他变量。
如果您使用 Apigee 配置 gRPC 服务器并将此政策添加到代理中,Apigee 将按如下方式处理 API 请求:
- Apigee 会向 gRPC 服务器发送包含流变量的消息。
- 系统将执行 gRPC 服务器代码并根据代码定义访问和修改变量。之后,gRPC 服务器会将包含所有流变量的响应发送回 Apigee。
- Apigee 将从 gRPC 服务器读取响应。如果添加了任何变量或修改了任何可修改的流变量,则系统会在 Apigee 中相应进行更新。
此政策为标准政策,可部署到任何环境类型。如需了解政策类型以及在每种环境类型中的可用性,请参阅政策类型。
如需详细了解如何发送 gRPC 请求,请参阅以下链接:
<ExternalCallout>
定义 ExternalCallout 政策。
<ExternalCallout async="true" continueOnError="true" enabled="true" name="EC">
此元素具有所有政策中常见的以下属性:
| 属性 | 默认 | 是否必需? | 说明 |
|---|---|---|---|
name |
无 | 必需 |
政策的内部名称。 (可选)使用 |
continueOnError |
false | 可选 | 设置为 false 可在政策失败时返回错误。这是大多数政策的预期行为。设置为 true,即使在政策失败后,仍可以继续执行流。另请参阅:
|
enabled |
true | 可选 | 设置为 true 可实施政策。 设为 false 可关闭政策。即使政策仍附加到某个流,也不会强制执行该政策。 |
async |
false | 已弃用 | 此属性已弃用。 |
下表介绍了 <ExternalCallout> 的子元素。
| 子元素 | 需要 | 说明 |
|---|---|---|
<TimeoutMs> |
需要 | gRPC 请求的请求超时(以毫秒为单位)。 |
<GrpcConnection> |
需要 | 指定现有 TargetServer 的名称,作为向其发送请求的 gRPC 服务器。 |
<Configurations> |
可选 | 允许您配置 ExternalCallout 政策的各个方面,包括 <Property> 和 <FlowVariable> 元素。 |
示例 1
如需查看 ExternalCallout 的工作示例,请参阅 GitHub 上的外部 Callout 示例。
以下示例展示了 ExternalCallout 政策配置。
<ExternalCallout enabled="true" continueOnError="false" name="ExternalCallout-1"> <DisplayName>External Callout 1</DisplayName> <TimeoutMs>5000</TimeoutMs> <GrpcConnection> <Server name="external-target-server"/> </GrpcConnection> <Configurations> <Property name="with.request.content">true</Property> <Property name="with.request.headers">false</Property> <Property name="with.response.content">true</Property> <Property name="with.response.headers">false</Property> <FlowVariable>example1.flow.variable</FlowVariable> <FlowVariable>example2.flow.variable</FlowVariable> </Configurations> <ExternalCallout>
该示例将向用名为 external-target-server 的
TargetServer 表示的外部 gRPC 服务器发送请求,其配置如下:
<Property>:在发送到 gRPC 服务器的请求中包含请求和响应内容,但不包含请求和响应标头。<FlowVariable>:在发送到 gRPC 服务器的请求中包含由FlowVariable元素指定的额外流变量example1.flow.variable和example2.flow.variable。
示例 2
在以下示例中,Audience 元素的 useTargetUrl 特性设置为 true。当 useTargetUrl 为 true 时,gRPC 目标服务器的主机名用作目标对象。例如,如果服务器的主机是 my-grpc-server-java.a.run.app,则使用的目标对象将为 https://my-grpc-server-java.a.run.app。
<ExternalCallout continueOnError="false" enabled="true" name="External-Callout-1"> <DisplayName>External-Callout-1</DisplayName> <GrpcConnection> <Server name="cloud_run_server_name"/> <Authentication> <GoogleIDToken> <Audience useTargetUrl="true"/> </GoogleIDToken> </Authentication> </GrpcConnection> <TimeoutMs>5000</TimeoutMs> <Configurations> <Property name="with.request.content">true</Property> <Property name="with.request.headers">true</Property> <Property name="with.response.content">true</Property> <Property name="with.response.headers">true</Property> <FlowVariable>example.flow.variable</FlowVariable> <FlowVariable>another.flow.variable</FlowVariable> </Configurations> </ExternalCallout>
子元素参考
以下部分介绍了 ExternalCallout 的子元素。
<TimeoutMs>
gRPC 请求的请求超时(以毫秒为单位)。 <TimeoutMs> 必须为正数。
<GrpcConnection>
<GrpcConnection> 元素将 gRPC 服务器设置为由 name 属性指定的现有 TargetServer。请参阅 TargetServer 资源参考页面。
注意:TargetServer 的协议必须是 GRPC。
例如,下面的代码
<GrpcConnection> <Server name="external-target-server"/> </GrpcConnection>
将 gRPC 服务器指定为名为 external-target-server 的现有 TargetServer。
使用 <Authentication> 元素(本部分稍后将介绍)生成 Google 签发的 OpenID Connect 令牌,以便对基于 gRPC 的服务(例如 Cloud Run 中托管的自定义服务)进行经过身份验证的调用。
下表介绍了 <GrpcConnection> 的子元素。
| 子元素 | 是否必需? | 说明 |
|---|---|---|
<Server> 元素 |
必需 | 指定 gRPC 服务器。 |
<Authentication> 元素 |
可选 | 生成 Google 签发的 OpenID Connect 令牌,以便对基于 gRPC 的服务(例如 Cloud Run)进行经过身份验证的调用。 |
<Server> 元素
指定 gRPC 服务器。
下表介绍了 <Server> 元素的属性。
| 属性 | 说明 | 默认值 | 状态 | 类型 |
|---|---|---|---|---|
name |
现有 |
不适用 | 需要 | 字符串 |
<Authentication> 元素
生成 Google 签发的 OpenID Connect 令牌,以便对基于 gRPC 的服务(例如 Cloud Run 中托管的自定义服务)进行经过身份验证的调用。使用此元素需要执行使用 Google 身份验证中所述的设置和部署步骤。正确设置后,政策会为您创建身份验证令牌,并将其添加到服务请求中。
此元素有一个必需的子元素:GoogleIDToken。
| 默认 | 不适用 |
| 是否必需? | 可选。 |
| 类型 | 复杂类型 |
| 父元素 | <GrpcConnection> |
| 子元素 |
<GoogleIDToken> |
Authentication 元素使用以下语法:
语法
<ExternalCallout> ... <GrpcConnection> <Server name="cloud_run_server_name"/> <Authentication> <HeaderName ref="FLOW_VARIABLE">STRING</HeaderName> <GoogleIDToken> <Audience ref="variable-1">STRING</Audience> <IncludeEmail ref="variable-2">BOOLEAN</IncludeEmail> </GoogleIDToken> </Authentication> </GrpcConnection> </ExternalCallout>
示例
以下示例展示了 GoogleIDToken 元素:
<ExternalCallout continueOnError="false" enabled="true" name="External-Callout-1"> <DisplayName>External-Callout-1</DisplayName> <GrpcConnection> <Server name="cloud_run_server_name"/> <Authentication> <HeaderName ref='my-variable'>X-Serverless-Authorization</HeaderName> <GoogleIDToken> <Audience>https://cloudrun-hostname.a.run.app</Audience> </GoogleIDToken> </Authentication> </GrpcConnection> <TimeoutMs>5000</TimeoutMs> <Configurations> <Property name="with.request.content">true</Property> <Property name="with.request.headers">true</Property> <Property name="with.response.content">true</Property> <Property name="with.response.headers">true</Property> <FlowVariable>example.flow.variable</FlowVariable> <FlowVariable>another.flow.variable</FlowVariable> </Configurations> </ExternalCallout>
属性
无。
<HeaderName> 子元素
默认情况下,如果存在 Authentication 配置,Apigee 会生成不记名令牌,并将其注入到发送到目标系统的消息中的 Authorization 标头。HeaderName 元素可让您指定其他标头的名称来保存该不记名令牌。如果目标是使用 X-Serverless-Authorization 标头的 Cloud Run 服务,此功能尤其有用。Authorization 标头(如果存在)保持不变,并且也会在请求中发送。
| 默认 | 不适用 |
| 是否必需? | 否 |
| 类型 | 字符串 |
| 父元素 | <Authentication> |
| 子元素 | 无 |
HeaderName 元素使用以下语法:
语法
<ExternalCallout>
...
<Authentication>
<HeaderName ref="FLOW_VARIABLE">STRING</HeaderName>
<GoogleIDToken>
...
</GoogleIDToken>
</Authentication>
...
</ExternalCallout>包含静态字符串
在此示例中,生成的不记名令牌默认添加到发送到目标系统的名为 X-Serverless-Authorization 的标头中。Authorization 标头(如果存在)保持不变,并且也会在请求中发送。
<Authentication>
<HeaderName>X-Serverless-Authorization</HeaderName>
<GoogleIDToken>
<Audience>https://cloudrun-hostname.a.run.app</Audience>
</GoogleIDToken>
</Authentication>包含变量引用
在此示例中,生成的不记名令牌默认添加到发送到目标系统的名为 X-Serverless-Authorization 的标头中。如果 my-variable 具有值,系统将使用该值而不是默认字符串。Authorization 标头(如果存在)保持不变,并且也会在请求中发送。
<Authentication> <HeaderName ref='my-variable'>X-Serverless-Authorization</HeaderName> <GoogleIDToken> <Audience>https://cloudrun-hostname.a.run.app</Audience> </GoogleIDToken> </Authentication>
<GoogleIDToken> 子元素
生成 Google 签发的 OpenID Connect 令牌,以便对 Google 服务(例如 Cloud Run 中托管的自定义服务)进行经过身份验证的调用。
| 默认 | 不适用 |
| 是否必需? | 需要 |
| 类型 | 字符串 |
| 父元素 | <Authentication> |
| 子元素 | <Audience><IncludeEmail> |
GoogleIDToken 元素使用以下语法:
语法
<ExternalCallout> ... <GrpcConnection> <Server name="cloud_run_server_name"/> <Authentication> <GoogleIDToken> <Audience ref="context-variable" useTargetUrl='BOOLEAN'>STRING</Audience> <IncludeEmail ref="context-variable">BOOLEAN</IncludeEmail> </GoogleIDToken> </Authentication> </GrpcConnection> </ExternalCallout>
示例
以下示例展示了 GoogleIDToken 元素:
<Authentication>
<GoogleIDToken>
<Audience>https://httpserver0-bar.run.app</Audience>
<IncludeEmail>true</IncludeEmail>
</GoogleIDToken>
</Authentication>
<Audience> 子元素
生成的身份验证令牌的目标对象,例如令牌授予访问权限的 API 或账号。
如果 Audience 的值为空,ref 为空或解析为空值,且 useTargetUrl 为 true,则使用“https://”+ (gRPC 目标服务器的主机名)作为目标对象。例如,如果服务器的主机是 my-grpc-server-java.a.run.app,则使用的目标对象将为 https://my-grpc-server-java.a.run.app。
默认情况下,useTargetUrl 为 false。
<Audience>explicit-audience-value-here</Audience> or: <Audience ref='variable-name-here'/> or: <Audience ref='variable-name-here' useTargetUrl='true'/> or: <Audience useTargetUrl='true'/>
| 默认 | 不适用 |
| 是否必需? | 需要 |
| 类型 | 字符串 |
| 父元素 | <GoogleIDToken> |
| 子元素 | 无。 |
<IncludeEmail> 子元素
如果设置为 true,则生成的身份验证令牌将包含服务账号 email 和 email_verified 声明。
| 默认 | false |
| 是否必需? | 可选 |
| 类型 | Boolean |
| 父元素 | <GoogleIDToken> |
| 子元素 | 无。 |
<Configurations>
借助 <Configurations> 元素,您可以配置 ExternalCallout 政策的各个方面,包括 <Property> 和 <FlowVariable>。
下表介绍了 <Configurations> 的子元素。
| 子元素 | 是否必需? | 说明 |
|---|---|---|
<Property> |
必需 | 指定是否将请求/响应标头和/或内容发送到服务器。可能的值有 |
<FlowVariable> |
必需 | 指定应向服务器发送哪些额外的流变量。 |
<Property>
<Property> 元素指定是否将请求/响应标头和/或内容发送到服务器。可能的值为 true(将发送该项)或 false(不会发送该项)。默认值为 false。
下表介绍了 <Property> 元素的属性。
| 属性 | 说明 | 默认值 | 状态 | 类型 |
|---|---|---|---|---|
name |
指定将发送到服务器的内容。可能的
|
不适用 | 需要 | 字符串 |
<FlowVariable>
<FlowVariable> 元素指定将发送到服务器的额外流变量。<FlowVariable> 的值是变量的前缀,而不是完整的变量名称。例如,如果 a.b.c,则名为 a.b.c 的变量的值将被发送到服务器。同样,名为 a.b.c.my-variable 的变量的值也将被发送到服务器。但不会发送名为 a.x.another-variable 的变量的值,因为它没有前缀 a.b.c。以下是一些示例
<Configurations> <FlowVariable>a.b.c</FlowVariable> <FlowVariable>d.e.f</FlowVariable> </Configurations>
错误参考信息
部署错误
| 错误名称 | 原因 |
|---|---|
FAILED_PRECONDITION |
如果在使用 <Authentication> 标记配置代理时缺少服务账号,则会发生此错误。例如: Deployment of \"organizations/foo/apis/apiproxy/revisions/1\" requires a service account identity, but one was not provided with the request. |
PERMISSION_DENIED |
如果在使用 <Authentication> 标记配置代理时服务账号出现权限问题,则会发生此错误。可能的原因:
|
运行时错误
下表介绍了执行政策时可能发生的运行时错误。
| 故障代码 | HTTP Status | 原因 |
|---|---|---|
GrpcTlsInitFailed |
500 |
如果使用 gRPC 服务器初始化 TLS 时遇到任何问题(例如密钥库或信任库问题),则会出现此错误。 |
steps.externalcallout.[error_code] |
500 |
|
steps.externalcallout.ExecutionError |
500 |
如果在执行此政策期间发生任何其他异常,则会出现此错误。底层异常将在 faultstring 中显示。如果 gRPC 服务器的凭据出现问题,则错误将如下所示:
{
"fault": {
"faultstring": "Encountered the following exception while sending the gRPC request or
processing the response: [io.grpc.StatusRuntimeException: UNAVAILABLE: Credentials failed
to obtain metadata].",
"detail": {
"errorcode": "steps.externalcallout.ExecutionError"
}
}
}您可以查看 MP 的日志以进一步调试指针。 |
googletoken.EmptyIDTokenAudience |
500 |
|
steps.externalcallout.ExecutionError
包含故障字符串:
|
500 |
如果为 API 代理配置了
|
带有包含 PERMISSION DENIED 的故障字符串的 steps.externalcallout.ExecutionError。例如,Cloud Run 的故障字符串如下所示:
|
500 |
如果为 API 代理配置了
|
其他错误
下表介绍了其他错误。如需了解详情,请参阅错误原因。
| 故障代码 | 原因 |
|---|---|
ReferencesExistToGrpcServer |
如果用户尝试删除 gRPC 目标服务器,但其他政策仍在使用该服务器,则会出现此错误。 |
错误
系统默认为所有政策设置下表中的故障变量。请参阅政策错误特有的变量。
| 变量 | 地点 | 示例 |
|---|---|---|
fault.name="fault_name" |
fault_name 是故障名称,如上面的运行时错误表中所列。故障名称是故障代码的最后一部分。 |
fault.name 会匹配“ExecutionError”。 |
externalcallout.[policy_name].failed |
policy_name 是抛出故障的政策的用户指定名称。 |
externalcallout.ExternalCallout-1.failed = true |