函数计算是一个事件驱动的服务。函数的执行可以由事件驱动,即当某个事件发生时,该事件触发函数的执行。现在,函数计算支持以 API 网关作为事件源。当请求设置函数计算为后端服务的 API 时,API 网关会触发相应的函数,函数计算会将执行结果返回给 API 网关。

1 功能简介

API 网关与函数计算对接,可以让您以 API 形式安全地对外开放您的函数,并且解决认证、流量控制、数据转换等问题(功能概览)。

API网关目前支持2种形式的函数,HTTP函数事件函数,下面将分别介绍这两种函数的对接方法。

2 HTTP函数对接API网关

HTTP函数是函数计算创建的一个带HTTP触发器的函数。配置方法如下。

2.1. 创建服务。登录 函数计算控制台,选择您要创建服务和函数的区域,单击新建服务,并在弹出的对话框中完成服务创建。注意:服务创建成功后,无法更换Region,请 谨慎选择所属区域,建议和API网关选择同一个区域。

2.2. 创建函数。在服务页面上,单击 新建函数 进入函数创建流程:

a. 选择HTTP函数

注意配置触发器时,认证方式尽量选择“function”,表示调用时需要进行认证和签名调用, 如果选择“anonymous”,则该函数支持匿名访问,不安全。

请求方式根据实际情况填写支持的Method,可以多选。

b. 接下来可以在 代码执行 页面进行代码编写和调试。

c. 在 触发器 页面查看触发器相关配置

2.3. 在API网关控制台创建分组和API

a. 单击控制台左侧导航栏中分组管理,选择分组列表的区域,再单击创建分组。(如果已创建分组,请忽略此步骤。)

说明 如果函数计算与 API 不在同一地域,将通过公网访问您的函数计算服务。若您对数据安全和网络延迟有较高要求,请选择API 与函数计算为同一地域。
b. 创建和定义 API。在API列表页面,点击创建API,进行API定义配置,您可根据实际情况填写相关配置在后端基础定义页面中,后端类型选择:函数计算:

调用方式: 选择“HTTP触发器”,

触发器路径: 请拷贝函数计算控制台触发器页面中的路径(见上图2.2中c步骤的触发器页面的路径);

后端请求path: 可以自定义path,如果不需要自定义,请填写"/"

HTTP Method: 请选择后端函数计算支持的method, 如果多个请选择"any".

角色Arn: 您需要授权API网关访问您的函数计算服务。单击获取授权,自动获取角色 Arn。如果这是您第一次获取函数计算为 API 网关后端服务的角色授权,当您单击获取授权后,会弹出 RAM 控制台的授权页面。您需单击 RAM 控制台的授权权限,然后返回 API 创建页面再次单击获取授权,该角色Arn将自动显示在选项框中。如果是子账号操作,需要主账号给子账号授权RAM的查询和操作权限。然后点击“下一步”,在页面上配置返回内容,这部分仅用于生成文档使用,不对API网关的返回产生影响。

2.4. 发布API,将API发布到测试或者线上环境,然后授权给某个APP(如果API的认证方式是“无认证”,则无需授权)。

2.5. 调试API。通过API列表,点击API名称,进入API详情,在左侧菜单中点击“调试API”,进入调试页面。

透传模式可以自行配置调用参数,进行API调试。

3 事件函数对接API网关创建服务

3.1 选择您要创建服务和函数的 所属区域,单击 新建服务, 并在弹出对话框中完成服务创建。注意:服务创建成功后,无法更换区域,请谨慎选择所属区域。

3.2 在已创建的服务中,创建函数。在该服务页面上,单击新建函数,进入函数创建流程:

a. 选择函数模板。

函数计算控制台中,提供了 Node.js 6 环境的 API 网关后端实现模板 api-gateway-nodejs6 供您使用。

如果 api-gateway-nodejs6 模板不适用您的业务场景,请选择 事件函数。选择使用 事件函数 后,后续在运行环境中提交您自己编写的代码。请提前准备好代码包,以便上传。

b. 关于代码编写示例,可参见 API网关触发函数计算 文档中,编写函数代码 部分。

3.3 在API网关控制台创建分组和API

其过程和“HTTP函数对接API网关的第2.3部分”一样。这里只详细说明函数计算后端配置部分。

调用方式:选择 事件

区域选择选择函数计算服务所在region。如果函数计算与 API 不在同一地域,将通过公网访问您的函数计算服务。若您对数据安全和网络延迟有较高要求,请选择API 与函数计算为同一地域。

服务名称函数名称:请根据实际的函数计算名称填写。当不同环境分别对应不同的函数计算时。可以通过环境管理方式配置。

角色Arn: 您需要授权API网关访问您的函数计算服务。单击获取授权,自动获取角色 Arn。如果这是您第一次获取函数计算为 API 网关 后端服务的角色授权,当您单击获取授权后,会弹出 RAM 控制台的授权页面。您需单击 RAM 控制台的授权权限,然后返回 API 创建页面再次单击获取授权,该角色Arn将自动显示在选项框中。如果是子账号操作,需要主账号给子账号授权RAM的查询和操作权限。

3.4. 发布API,将API发布到测试或者线上环境,然后授权给某个APP(如果API的认证方式是“无认证”,则无需授权)。

3.5. 调试API。通过API列表,点击API名称,进入API详情,在左侧菜单中点击“调试API”,进入调试页面。透传模式可以自行配置调用参数,进行API调试。

4. 事件函数对接API网关的格式要求

API 网关调用函数计算的事件函数时,会将 API 的相关数据转换为 Map 形式传给函数计算服务。函数计算服务处理后,按照下图中 Output Format 的格式返回 statusCode、headers、body 等相关数据。API 网关再将函数计算返回的内容映射到 statusCode、header、body等位置返回给客户端。

API 网关向函数计算传入参数格式:

当以函数计算作为 API 网关的后端服务时,API 网关会把请求参数通过一个固定的 Map 结构传给函数计算的入参 event。函数计算通过如下结构去获取需要的参数,然后进行处理。

{
	"path":"api request path",
	"httpMethod":"request method name",
	"headers":{all headers,including system headers},
	"queryParameters":{query parameters},
	"pathParameters":{path parameters},
	"body":"string of request payload",
	"isBase64Encoded":"true|false, indicate if the body is Base64-encode"
}
  • 如果 "isBase64Encoded" 的值为 "true",表示 API 网关传给函数计算的 body 内容已进行 Base64 编码。函数计算需要先对 body 内容进行 Base64 解码后再处理。
  • 如果"isBase64Encoded" 的值为 "false",表示 API 网关没有对 body 内容进行 Base64 编码。

函数计算的返回参数格式:

函数计算需要将输出内容通过如下 JSON 格式返回给 API 网关,以便 API 网关解析。

{
	"isBase64Encoded":true|false,
	"statusCode":httpStatusCode,
	"headers":{response headers},
	"body":"..."
}
  • 当 body 内容为二进制编码时,需在函数计算中对 body 内容进行 Base64 编码,设置"isBase64Encoded" 的值为 "true"。如果 body 内容无需 Base64 编码,"isBase64Encoded" 的值为 "false"。API 网关会对 "isBase64Encoded" 的值为 "true" 的 body 内容进行 Base64 解码后,再返回给客户端。
  • 在 Node.js 环境中,函数计算根据不同的情况设置 callback。
    • 返回成功请求: callback{null,{"statusCode":200,"body":"..."}}。
    • 返回异常:callback{new Error('internal server error'),null}。
    • 返回客户端错误: callback{null,{"statusCode":400,"body":"param error"}}。
  • 如果函数计算返回不符合格式要求的返回结果,API 网关将返回 503 Service Unavailable 给客户端。

5 事件函数调用示例

以下提供三个示例,分别为:事件函数代码示例、API 请求示例、和 API 网关返回示例。

5.1 事件函数代码示例

在函数计算的代码执行页面配置的代码示例。

module.exports.handler = function(event, context, callback) {
    var responseCode = 200;
    console.log("request: " + JSON.stringify(event.toString()));
    //将event转化为JSON对象
    event=JSON.parse(event.toString());
    var isBase64Encoded=false;
	//根据用户输入的statusCode返回,可用于测试不同statusCode的情况
    if (event.queryParameters !== null && event.queryParameters !== undefined) {
        if (event.queryParameters.httpStatus !== undefined && event.queryParameters.httpStatus !== null && event.queryParameters.httpStatus !== "") {
            console.log("Received http status: " + event.queryParameters.httpStatus);
            responseCode = event.queryParameters.httpStatus;
        }
    }
    //如果body是Base64编码的,FC中需要对body内容进行解码
    if(event.body!==null&&event.body!==undefined){
    	if(event.isBase64Encoded!==null&&event.isBase64Encoded!==undefined&&event.isBase64Encoded){
    		event.body=new Buffer(event.body,'base64').toString();
    	}
    }
    //input是API网关给FC的输入内容
    var responseBody = {
        message: "Hello World!",
        input: event
    };
	
	//对body内容进行Base64编码,可根据需要处理
    var base64EncodeStr=new Buffer(JSON.stringify(responseBody)).toString('base64');
	
	//FC给API网关返回的格式,须如下所示。isBase64Encoded根据body是否Base64编码情况设置
    var response = {
		isBase64Encoded:true,
		statusCode: responseCode,
		headers: {
		"x-custom-header" : "header value"
		},
		body: base64EncodeStr
    };
    console.log("response: " + JSON.stringify(response));
    callback(null, response);
};	

5.2 事件函数请求示例

以 POST 形式请求 path 为如下的 API:

/fc/test/invoke/[type]	
发起请求如下:
POST http://test.alicloudapi.com/fc/test/invoke/test?param1=aaa&param2=bbb

"X-Ca-Signature-Headers":"X-Ca-Timestamp,X-Ca-Version,X-Ca-Key,X-Ca-Stage",
"X-Ca-Signature":"TnoBldxxRHrFferGlzzkGcQsaezK+ZzySloKqCOsv2U=",
"X-Ca-Stage":"RELEASE",
"X-Ca-Timestamp":"1496652763510",
"Content-Type":"application/x-www-form-urlencoded; charset=utf-8",
"X-Ca-Version":"1",
"User-Agent":"Apache-HttpClient\/4.1.2 (java 1.6)",
"Host":"test.alicloudapi.com",
"X-Ca-Key":"testKey",
"Date":"Mon, 05 Jun 2017 08:52:43 GMT","Accept":"application/json",
"headerParam":"testHeader"

{"bodyParam":"testBody"}	
5.3 API网关返回示例
200
Date: Mon, 05 Jun 2017 08:52:43 GMT
Content-Type: application/json; charset=UTF-8
Content-Length: 429
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS , PATCH
Access-Control-Allow-Headers: X-Requested-With, X-Sequence,X-Ca-Key,X-Ca-Secret,X-Ca-Version,X-Ca-Timestamp,X-Ca-Nonce,X-Ca-API-Key,X-Ca-Stage,X-Ca-Client-DeviceId,X-Ca-Client-AppId,X-Ca-Signature,X-Ca-Signature-Headers,X-Forwarded-For,X-Ca-Date,X-Ca-Request-Mode,Authorization,Content-Type,Accept,Accept-Ranges,Cache-Control,Range,Content-MD5
Access-Control-Max-Age: 172800
X-Ca-Request-Id: 16E9D4B5-3A1C-445A-BEF1-4AD8E31434EC
x-custom-header: header value

{"message":"Hello World!","input":{"body":"{\"bodyParam\":\"testBody\"}","headers":{"X-Ca-Api-Gateway":"16E9D4B5-3A1C-445A-BEF1-4AD8E31434EC","headerParam":"testHeader","X-Forwarded-For":"100.81.146.152","Content-Type":"application/x-www-form-urlencoded; charset=UTF-8"},"httpMethod":"POST","isBase64Encoded":false,"path":"/fc/test/invoke/test","pathParameters":{"type":"test"},"queryParameters":{"param1":"aaa","param2":"bbb"}}}
	

6 常见问题

6.1 为什么我无法录入我已有的函数?

请确认您输入的函数计算的服务名称和函数名称是否与您在函数计算控制台创建的服务和函数的名称一致。