自定义响应体

最近更新时间:2023-11-10 10:05:52

我的收藏

操作场景

API 网关响应给客户端响应体中包含很多字段,如果您需要修改响应体内容,可以通过自定义响应体插件实现。
自定义请求体插件作用在响应过程中, 响应内容改写服务可部署在云函数、公网、或内网 VPC 上。业务后端处理完请求报文后,会将响应体传递给 API 网关。API 网关接收到响应内容后,API 网关会将响应内容转发到响应体修改服务中,响应体内容修改完成后,将修改后的响应体响应给 API 网关,API 网关再将修改后的响应体转发给业务后端。




前提条件

目前已支持云函数、公网、或内网 VPC ,故满足三者任意一个,均可使用。
1. 已开通 云函数 服务。
2. 已存在公网服务。
3. 已开通 私有网络 服务。
说明:
自定义请求体插件目前仅支持事件函数,不支持 Web 函数。

操作步骤

以下以云函数为例。

步骤1:创建修改响应体的函数

1. 登录 云函数控制台
2. 在左侧导航栏,单击函数服务,进入函数列表页。
3. 单击页面左上角的新建,新建一个函数,内容为修改响应体。

步骤2:创建自定义响应体插件

1. 登录 API 网关控制台
2. 在左侧导航栏,单击插件 > 自定义插件,进入自定义插件列表页。
3. 单击页面左上角的新建,新建一个自定义响应体插件。
对于部署在云函数的认证服务,创建自定义响应插件时需要填写的数据如下:
参数
是否必填
说明
选择函数
必填
选择修改响应体的函数所在的命名空间、名称和版本。
Base64 编码
必填
业务后端响应内容传到云函数中时是否要经过 Base64 编码,一般适用于响应内容是二进制的情况。
后端超时
必填
设置 API 网关转发到修改响应体的函数的后端超时时间,超时时间的最大限制为30分钟。在 API 网关调用修改响应体的函数,未在超时时间内获得响应时,API 网关将终止此次调用,并返回相应的错误信息。
自定义内容
必填
设置 API 网关发送给修改响应体的函数的响应内容,支持选择 Header、Body、状态码。未选择的响应内容部分将不被修改,直接转发给客户端。
对于部署在公网的认证服务,创建自定义响应插件时需要填写的数据如下:
参数
是否必填
说明
请求方法
必填
请求自定义响应体函数的方法,支持 GET、POST、PUT、DELETE、HEAD、ANY。
公网服务
必填
自定义响应体改写服务访问地址,支持 HTTP 和 HTTPS 协议。
路径匹配模式
必填
支持后端路径匹配和全路径匹配两种方式。
后端路径匹配:直接使用配置的路径请求服务。
全路径匹配:使用去除请求路径的路径请求服务,如 API 路径配置为 /a/,请求路径为 /a/b,开启全路径匹配后,传输给服务的为 /b。



对于部署在内网 VPC 的认证服务,创建自定义响应插件时需要填写的数据如下:
参数
是否必填
说明
选择 VPC
必填
选择响应体改写服务所属的 VPC。
请求方法
必填
请求响应体改写函数的方法,支持 GET、POST、PUT、DELETE、HEAD、ANY。
后端地址
必填
响应体改写服务访问地址,支持 HTTP 和 HTTPS 协议。




步骤3:绑定 API

1. 在插件列表中选中 步骤2 创建好的插件,单击操作列的绑定 API
2. 在绑定 API 弹窗中选择服务和环境,并选择需要绑定插件的 API。



3. 单击确定,即可将插件绑定到 API,此时插件的配置已经对 API 生效。

pluginData

{
"endpoint_timeout":15, // 后端超时时间,单位秒,合法值:0 ~ 60 秒
"func_name":"test_name", // 自定义函数名称
"func_namespace":"test_namespace", // 自定义函数命名空间
"func_qualifier":"$LATEST", // 自定义函数版本
"is_base64_encoded":true, // 业务后端响应内容传到云函数中时是否要经过Base64编码
"is_custom_status":true, // 是否将响应的状态码内容发送到函数
"is_custom_headers":true, // 是否将响应的Header内容发送到函数
"is_custom_body":true, // 是否将响应的Body内容发送到函数
"user_id":1253970226 // appid
}

注意事项

每次将自定义插件绑定到一个网关 API 时,相当于为修改响应体的函数创建了一个该网关 API 的触发器。在 SCF 侧删除触发器,相当于把插件和 API 解绑。
自定义响应体插件优先级低于所有作用在请求过程中的插件。
自定义响应体插件绑定到后端为 Mock、微服务平台 TSF 的 API 上时,将不生效。
自定义响应体插件不支持 HTTP2 协议。
自定义响应体插件不支持后端返回经 gzip 压缩后的响应体。

自定义服务类型规则

自定义插件的自定义服务类型,支持绑定不同实例上的服务 API,规则请参见 插件概述-已支持自定义插件类型

示例代码

自定义响应体时,HTTP 服务的示例代码如下:
Python 2.7
from http.server import BaseHTTPRequestHandler, HTTPServer from urllib.parse import urlparse, parse_qs import json PORT_NUMBER = 8022 def handle_header(header, response): replace_headers = {} # 需要替换或者新增的header remove_headers = [] # 需要删除的header # 示例:替换或新增 header1 replace_headers["header1"] = "header1" # 示例:删除 X-Api-Serviceid remove_headers.append("X-Api-Serviceid") response["replace_headers"] = replace_headers response["remove_headers"] = remove_headers def handle_body(body, header, response): response["replace_body"] = "replace_body" # 是否需要对replace_body 进行base64解码 response["is_base64_encoded"] = header.get("is_base64_encoded") def handle_status(header, response): status = header.get("status") # 示例:后端错误处理 if status is not None and status != 200: response["replace_status"] = 200 response["replace_body"] = "custom response, upstream_status is " + str(status) response["is_base64_encoded"] = False class MyHandler(BaseHTTPRequestHandler): def _set_headers(self): self.send_response(200) self.send_header('Content-type', 'application/json') self.end_headers() def do_POST(self): response = {} try: request_body = self.rfile.read(int(self.headers.getheader("Content-length"))) except: request_body = "no body." # 重写header handle_header(self.headers.__dict__, response) # 重写status handle_status(self.headers.__dict__, response) # 重写body handle_body(request_body, self.headers.__dict__, response) self._set_headers() self.wfile.write(json.dumps(response).encode('utf-8')) return def do_GET(self): response = { 'api-auth': True } # header认证 header_auth_key = self.headers.get("header-auth") if header_auth_key == "apigw": response['api-auth'] = False # query认证 parsed_url = urlparse(self.path) query_params = parse_qs(parsed_url.query) query_auth_key = query_params.get("query-auth", [None])[0] if query_auth_key == "apigw": response['api-auth'] = False self._set_headers() self.wfile.write(json.dumps(response).encode('utf-8')) return try: server = HTTPServer(('', PORT_NUMBER), MyHandler) print(f'Started HTTP server on port {PORT_NUMBER}') # Wait forever for incoming http requests server.serve_forever() except KeyboardInterrupt: print('^C received, shutting down the web server') server.socket.close()