本文介绍自定义运行时中函数调用的方式、使用限制及代码示例。
背景信息
自定义运行时支持托管用户的HTTP Server,并将函数调用的请求转换为HTTP请求发送到HTTP Server,将HTTP Server的响应转换为函数调用的响应返回给Client。过程示意如下:
函数调用的方式有两种,分别为:
-
HTTP调用(推荐):使用HTTP方式调用,例如使用HTTP触发器或者自定义域名来调用。
-
API调用:通过InvokeFunction API进行调用,例如使用SDK调用函数或者通过事件源触发函数。
调用方式的不同,用户的HTTP Server的请求和响应的格式也会不同。
使用限制
-
HTTP Request限制
-
Request Headers不支持以x-fc-开头的自定义字段和以下自定义字段:
-
connection
-
keep-alive
-
-
如果Request超过以下限制,会返回
400状态码和InvalidArgument错误码。-
Headers大小:Headers中的所有Key和Value的总大小不得超过8 KB。
-
Path大小:包括所有的Query Params,Path的总大小不得超过4 KB。
-
Body大小:同步调用请求的Body的总大小不得超过32 MB,异步调用请求的Body的总大小不得超过128 KB。
-
-
-
HTTP Response限制
-
Response Headers不支持以x-fc-开头的自定义字段和以下自定义字段:
-
connection
-
content-length
-
date
-
keep-alive
-
server
-
content-disposition:attachment
说明从安全角度考虑,使用函数计算默认的aliyuncs.com域名,服务端会在Response Headers中强制添加content-disposition: attachment字段,此字段会使得返回结果在浏览器中以附件的方式下载。如果需要解除该限制,需配置自定义域名。
-
-
如果Response超过以下限制,会返回
502状态码和BadResponse错误码。-
Headers大小:Headers中的所有Key和Value的总大小不得超过8 KB。
-
-
-
其他使用说明
您可以通过绑定自定义域名,为函数映射不同的HTTP访问路径。详细信息,请参见配置自定义域名。
HTTP调用(推荐)
对于HTTP方式的调用,函数计算采用透传模式,即将Client的HTTP请求透传到用户的HTTP Server,并且将HTTP Server的响应透传给Client。一些系统保留的字段将不会透传,具体请参考使用限制。
请求头(HTTP Request Header)
使用HTTP触发器或者自定义域名调用函数时,函数计算支持使用配置请求头控制请求的行为,具体如下表所示。
|
名称 |
类型 |
是否必选 |
示例 |
描述 |
|
X-Fc-Invocation-Type |
String |
否 |
Sync |
调用方式,具体信息请参见调用方式。取值说明如下:
|
|
X-Fc-Log-Type |
String |
否 |
Tail |
请求返回日志。取值说明如下:
|
响应头(HTTP Response Header)
使用HTTP触发器或自定义域名调用函数时,响应中会包含函数计算默认添加的一些响应头,具体如下表所示。
|
名称 |
描述 |
示例值 |
|
X-Fc-Request-Id |
函数调用的请求ID。 |
dab25e58-9356-4e3f-97d6-f044c4**** |
API调用
对于使用InvokeFunction API的调用,函数计算会将InvokeFunction请求转换成HTTP请求,传递给用户的HTTP Server,转换的规则如下:
-
InvokeFunction的event参数被转换成HTTP请求的消息体。
-
path为/invoke。 -
method为POST。 -
Content-Type消息头为application/octe-stream。
函数计算会将用户HTTP Server的响应转换为InvokeFunction的响应返回给客户端,转换的规则如下:
-
HTTP响应体转换成InvokeFunction的响应体。
-
在转换过程中会丢失HTTP响应头和状态码信息。
Invoke API 请求的转换示例
|
Invoke请求 |
HTTP Request (HTTP Server收到的请求) |
|
Invoke API 请求内容:
|
|
Invoke API 响应的输出示例
|
HTTP Response |
Invoke响应 |
|
|
|
|
函数计算响应码和响应头
Custom Runtime本质是您实现的HTTP Server,因此每一次函数调用都是一次HTTP请求,即每次响应都有响应码和响应头。
-
响应码
StatusCode-
200:成功状态。 -
404:失败状态。
-
-
响应头
x-fc-status-
200:成功状态。 -
404:失败状态。
-
通过Headers中的x-fc-status响应,向函数计算汇报本地函数是否执行成功。
-
不设置
x-fc-status:函数计算默认本次调用是成功执行的,但是您的函数可能有异常,没有向函数计算汇报,函数计算会认为这次函数执行没有报错,在业务逻辑上可能没有影响,但是在监控可观测性上会有影响。如以下代码所示:print("FC Invoke Start RequestId: " + rid) data = request.stream.read() print("Path: " + path) print("Data: " + str(data)) # 模拟异常:触发一个运行时错误 raise Exception("mock exception") print("FC Invoke End RequestId: " + rid) return "Hello, World!" if __name__ == '__main__': app.run(host='0.0.0.0', port=9000) -
设置
x-fc-status:当您的函数存在异常,通过x-fc-status响应向函数计算汇报本次函数执行失败,并将错误堆栈信息打印到日志中。如下所示:设置x-fc-status响应头为404后,函数计算将本次调用识别为执行失败,错误类型为InvocationError,返回结果为mock exception。app.py 示例代码:@app.route('/', defaults={'path': ''}) @app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE']) def hello_world(path): rid = request.headers.get(REQUEST_ID_HEADER) print("FC Invoke Start RequestId: " + rid) try: raise Exception("mock exception") except Exception as e: print("FC Invoke End RequestId: " + rid + ", Error: Unhandled Exception") print(str(e)) return str(e), 404, [{"x-fc-status", "404"}]
在返回的HTTP响应中,建议您同时设置StatusCode和x-fc-status。
代码示例
当函数配置触发器时,您可以使用任意语言实现HTTP Server。本文以Python为例,代码示例如下。
该示例代码依赖Python环境和Flask库,建议创建函数方式选择Web 函数,运行环境选择Python 3.10。
import os
from flask import Flask
from flask import request
REQUEST_ID_HEADER = 'x-fc-request-id'
app = Flask(__name__)
@app.route('/', defaults={'path': ''})
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE'])
def hello_world(path):
rid = request.headers.get(REQUEST_ID_HEADER)
data = request.stream.read()
print("Path: " + path)
print("Data: " + str(data))
return "Hello, World!", 200, [('Function-Name', os.getenv('FC_FUNCTION_NAME'))]
if __name__ == '__main__':
app.run(host='0.0.0.0', port=9000)
示例解析如下:
-
@app.route('/', defaults={'path': ''}):默认路由,对应根路径。 -
@app.route('/<path:path>', methods=['GET', 'POST', 'PUT', 'DELETE']):带有路径参数的动态路由,可以处理GET、POST、PUT、DELETE请求。路径参数的值将被传递给hello_world函数作为参数path。 -
rid = request.headers.get(REQUEST_ID_HEADER):获取请求头中的x-fc-request-id字段的值。 -
data = request.stream.read():读取请求的内容,并将其赋值给变量data。 -
return "Hello, World!", 200, [('Function-Name', os.getenv('FC_FUNCTION_NAME'))]:返回一个包含"Hello, World!"的响应体,并设置状态码为200及一个包含Function-Name头部的元组。