本文介绍自定义运行时中函数调用的方式、使用限制及代码示例。
背景信息
自定义运行时支持托管用户的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响应 |
|
|
|
|
代码示例
您可以使用任意语言实现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
头部的元组。