Custom Container代码开发

本文介绍Custom Container中函数调用的方式、使用限制及代码示例。

背景信息

Custom Container支持托管用户的HTTP Server,并将函数调用的请求转换为HTTP请求发送到HTTP Server,将HTTP Server的响应转换为函数调用的响应返回给Client。过程示意如下:

image

函数调用的方式有两种,分别为:

  • HTTP调用(推荐):使用HTTP方式调用,例如使用HTTP触发器或者自定义域名来调用。

  • API调用:通过InvokeFunction API进行调用,例如使用SDK调用函数或者通过事件源触发函数。

调用方式的不同,用户的HTTP Server的请求和响应的格式也会不同。

使用限制

  • 一个函数的一个版本或别名,最多只能创建一个HTTP触发器。详细信息,请参见管理版本管理别名

  • 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

调用方式,具体信息请参见调用方式。取值说明如下:

  • Sync:同步调用。

  • Async:异步调用。

X-Fc-Log-Type

String

Tail

请求返回日志。取值说明如下:

  • Tail:返回当前请求产生的最后4 KB日志。

  • None:默认值,不返回请求日志。

响应头(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

  • methodPOST

  • Content-Type消息头为application/octe-stream

函数计算会将用户HTTP Server的响应转换为InvokeFunction的响应返回给客户端,转换的规则如下:

  • HTTP响应体转换成InvokeFunction的响应体。

  • 在转换过程中会丢失HTTP响应头和状态码信息。

Invoke API 请求的转换示例

Invoke请求

HTTP Request (HTTP Server收到的请求)

Invoke API 请求内容:

"hello world"
> POST /invoke HTTP/1.1
> Host: 21.0.0.3
> Content-Length: 11
> Content-Type: application/octet-stream

hello world

Invoke API 响应的输出示例

HTTP Response

Invoke响应

< HTTP/1.1 200 OK
< Date: Mon, 10 Jul 2023 07:02:15 GMT
< Content-Type: application/json
< Content-Length: 11
< Connection: keep-alive

hello world

hello world
< HTTP/1.1 400 Bad Request
< Date: Mon, 10 Jul 2023 07:02:15 GMT
< Content-Type: application/json
< Content-Length: 28
< Connection: keep-alive

{"errorMessage":"exception"}
{"errorMessage":"exception"}

代码示例

您可以使用任意语言实现HTTP Server。本文以Python为例,代码示例如下。

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头部的元组。