函数计算

函数计算是一个事件驱动的服务,将API网关与函数计算服务对接后,即可通过API形式安全地对外开放函数,并且解决认证、流量控制、数据转换等问题。本文以函数计算3.0为例介绍如何对接API网关与函数计算服务。

前提条件

创建API网关实例,关于实例的选型信息,请参考实例类型与选择指南

功能简介

API网关目前支持两种形式的函数计算服务,HTTP函数和事件函数。

HTTP函数对接API网关

创建Web函数

在配置API网关前,需要先在函数计算3.0控制台中创建一个Web函数。可参考创建Web函数

创建后端服务

在API网关中定义后端服务,并配置后端服务地址来对接函数计算服务。

  1. 登录API网关控制台,左侧导航栏选择API管理 > 后端服务,在顶部菜单栏选择地域,单击创建后端服务

    image

  2. 创建后端服务弹框中,按图所示填写配置信息,并单击确定

    image

  3. 在后端服务页面,单击刚刚创建的后端服务,进入后端服务定义页,选择线上页签,在基本信息处单击创建

    image

  4. 在创建的基本信息页面,配置触发器路径的访问地址,单击发布

    image

创建API

在API网关控制台上创建API,详情可参见创建API

  • API分组。建议API分组与函数计算在相同的地域。

说明

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

  • 创建和定义API。在“定义API后端服务”步骤中,如下图所示:

image

后端配置:使用已有的后端服务

后端服务类型:函数计算

产品版本:函数计算3.0

函数类型:HTTP函数

后端服务:选择已创建的后端服务名。

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

HTTP Method:请选择后端函数计算支持的method, 如果多个请选择“ANY”。

使用其他账号的函数计算

API网关除了使用相同账号下的函数计算服务外,还可以使用其他账号下的函数计算服务。以A账号下的API网关需要使用B账号下的函数计算为例,介绍如何操作。

  1. B账号为A账号API网关的访问函数计算授权。

    步骤1:使用B账号登录RAM控制台,创建RAM角色,参考创建可信实体为阿里云账号的RAM角色

    步骤2:为步骤1中创建的角色增加调用函数计算的授权。需要添加名为AliyunFCInvocationAccess的系统权限,参考在RAM角色管理页面为RAM角色授权

    步骤3:修改步骤1创建的角色的信任策略,参考 修改RAM角色的可信实体为阿里云账号。将A账号的AccountID(如123456789012****)添加到信任策略中,修改后的信任策略如下:

    {
      "Statement": [
        {
          "Action": "sts:AssumeRole",
          "Effect": "Allow",
          "Principal": {
            "Service": [
              "123456789012****@apigateway.aliyuncs.com"
            ]
          }
        }
      ],
      "Version": "1"
    }

    步骤4:B账号将步骤1创建的角色的Arn(了解 RAM角色基本概念)提供给A账号。

  2. A账号在API网关控制台中添加访问B账号的函数计算服务。其中触发路径内容为B账号下的函数计算服务的访问地址,角色Arn中填写B账号提供的角色Arn名称。

重要

当后端服务为HTTP函数时,客户端发送的Authorization参数值会被HTTP函数的Authorization覆盖,建议客户端更换参数名称。

事件函数对接API网关

创建事件触发函数

在函数计算3.0控制台创建事件函数可参见创建事件函数

创建后端服务

在API网关中定义后端服务,并配置后端服务地址来对接函数计算服务。

  1. 登录API网关控制台,选择地域并在左侧导航栏选择API管理 > 后端服务,单击右上角创建后端服务,配置如下信息,单击确定。

    image

  2. 在后端服务页面,单击刚刚创建的后端服务,进入后端服务定义页,选择线上页签,在基本信息处单击创建

    image

  3. 选择函数名称为所创建的事件函数,单击发布

    image

创建API

在API网关控制台上创建API,详情可参见创建API

  • API分组。建议API分组与函数计算在相同的地域。

说明

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

  • 创建API。在“定义API后端服务”步骤中,如下图所示:

image

后端配置:使用已有的后端服务

后端服务类型:函数计算

产品版本:函数计算3.0

函数类型:事件函数

后端服务:选择已创建的后端服务名。

事件函数对接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给客户端。

事件函数调用示例

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

事件函数代码示例

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

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);
};        

事件函数请求示例

以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"}        

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"}}}
        

常见问题

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

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

使用函数计算作为API后端服务时,API网关到后端服务是否可以走内网?

当选择事件函数时,API网关和函数计算在同一region时,默认走内网。