全部产品

以函数计算作为 API 网关后端服务

更新时间:2018-08-13 15:10:02

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

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

实现原理

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

实现原理

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

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

  1. {
  2. "path":"api request path",
  3. "httpMethod":"request method name",
  4. "headers":{all headers,including system headers},
  5. "queryParameters":{query parameters},
  6. "pathParameters":{path parameters},
  7. "body":"string of request payload",
  8. "isBase64Encoded":"true|false, indicate if the body is Base64-encode"
  9. }

注意:

  • 如果 "isBase64Encoded" 的值为 "true",表示 API 网关传给函数计算的 body 内容已进行 Base64 编码。函数计算需要先对 body 内容进行 Base64 解码后再处理。

  • 如果"isBase64Encoded" 的值为 "false",表示 API 网关没有对 body 内容进行 Base64 编码。

函数计算的返回参数格式

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

  1. {
  2. "isBase64Encoded":true|false,
  3. "statusCode":httpStatusCode,
  4. "headers":{response headers},
  5. "body":"..."
  6. }

注意:

  • 当 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 网关触发函数计算

配置 API 网关触发函数计算服务的操作步骤:

  1. 在函数计算控制台创建函数

  2. 创建并定义以函数计算为后端服务的 API

  3. 调试 API

  4. 将 API 发布到线上

在函数计算控制台创建函数

  1. 创建服务。登录 函数计算控制台, 选择您要创建服务和函数的 所属区域,单击 新建服务,并在弹出对话框中完成服务创建。

    注意:服务创建成功后,无法更换区域,请谨慎选择 所属区域

    新建服务

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

    1. 选择函数模板。

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

      如果 api-gateway-nodejs6 模板不适用您的业务场景,请选择 空白函数。选择使用 空白函数 模板后,在 基础管理配置 中需提交您自己编写的代码。请提前准备好代码包,以便上传。

      选择模板

    2. 触发器配置。触发器类型 选择为 不创建触发器,单击 下一步

    3. 基础管理配置:填写基础信息、配置代码、设置环境变量、和配置环境,再单击 下一步

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

      基础管理

    4. 请忽略权限配置,直接单击 下一步

      因为我们已在 RAM 控制台配置了相应的 roleArn 的权限,所以无需您手动配置。 您只需在 API 网关控制台创建 API 时,单击 获取授权, 即可自动获取授权。

    5. 核对信息,信息无误,则单击 创建

      成功创建函数后,您可以在 函数列表 中,查看所创建函数的基本信息。

创建并定义以函数计算为后端服务的 API

您需在 API 网关控制台 创建 API, 并定义此 API 的后端服务为函数计算。

  1. 登录 API 网关控制台

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

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

    创建API

    API 分组创建成功后,您可以通过 环境管理 为此分组设置环境变量。目前有三种环境:测试、预发、和线上。为避免环境转换导致后端地址变化,您可以通过增加环境变量参数的来实现请求的自动路由。环境变量配置方法,请参见 环境管理

  3. 创建和定义 API。

    1. 创建分组成功后,单击该分组操作栏中 API 管理 按钮,进入相应的 API 列表 页面。

    2. 单击 创建 API, 进入 API 创建和定义流程。

    3. 填写基本信息,再单击 下一步

      注意:如果选择类型为 私有,该 API 将不能在云市场上架。

      创建 API

    4. 定义 API 请求,再单击 下一步

      注意:如果 入参请求模式 选择为 入参透传,则发送给 API 网关的参数 body 内容不经处理,直接作为参数透传给函数计算。

      创建 API

    5. 定义 API 后端服务,再单击 下一步

      注意:在此页面,您需:

      • 选择 后端服务类型函数计算

      • 填写 服务名称 为您在 函数计算控制台 创建的服务名称。

      • 填写 函数名称 为您在 函数计算控制台 创建的函数名称。

      • 单击 获取授权,自动获取角色 Arn。

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

      定义后端服务

    6. 定义返回结果,然后单击 创建

      注意:返回结果示例为必填,且格式需遵循 函数计算的返回参数格式

      定义返回结果

      如需更多帮助,请参见 API 创建

调试 API

API 创建、定义完成后,页面自动跳转到 API 列表 页。您可以通过此页面按钮,对创建的 API 进行测试是否可用,请求链路是否正确。

  1. 单击 API 名称或 管理 按钮,进入 API 定义 页面。

  2. 单击左侧导航栏中 调试 API

  3. 输入请求参数,单击 发送请求

    返回结果将显示在右侧页面。

    如果调试返回成功结果,则说明该 API 可以使用。

    如果返回代码为 4XX 或 5XX,则表示存在错误。请参见 如何获取错误信息错误代码表

    调试

  4. 将 API 发布到 预发 环境,做上线前测试。

    测试证明 API 可用后,可返回 API 定义 页面,将 API 发布到 预发 环境。然后,通过访问二级域名来进行测试调用,模拟真实的用户请求。

    注意: 如果在 API 定义中设置了环境变量,需在请求 Header 中增加入参 X-Ca-Stage: RELEASE 才能正确调用预发环境的 API。

将 API 发布到线上

API 通过调试,证明可以使用后,可将 API 进行发布。

  1. API 列表 页面,单击 API 名称或 管理 按钮,进入 API 定义 页面。

  2. 单击页面右上方 发布 按钮,弹出 发布 API 对话框。

  3. 选择要发布的环境为线上,填写备注信息,单击 发布

    将 API 发布到线上后,您的用户便可以调用此 API。

    发布

更多发布相关细节,请参见文档 发布 API

示例

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

函数代码示例

在函数计算中配置的代码示例。

  1. module.exports.handler = function(event, context, callback) {
  2. var responseCode = 200;
  3. console.log("request: " + JSON.stringify(event.toString()));
  4. //将event转化为JSON对象
  5. event=JSON.parse(event.toString());
  6. var isBase64Encoded=false;
  7. //根据用户输入的statusCode返回,可用于测试不同statusCode的情况
  8. if (event.queryParameters !== null && event.queryParameters !== undefined) {
  9. if (event.queryParameters.httpStatus !== undefined && event.queryParameters.httpStatus !== null && event.queryParameters.httpStatus !== "") {
  10. console.log("Received http status: " + event.queryParameters.httpStatus);
  11. responseCode = event.queryParameters.httpStatus;
  12. }
  13. }
  14. //如果body是Base64编码的,FC中需要对body内容进行解码
  15. if(event.body!==null&&event.body!==undefined){
  16. if(event.isBase64Encoded!==null&&event.isBase64Encoded!==undefined&&event.isBase64Encoded){
  17. event.body=new Buffer(event.body,'base64').toString();
  18. }
  19. }
  20. //input是API网关给FC的输入内容
  21. var responseBody = {
  22. message: "Hello World!",
  23. input: event
  24. };
  25. //对body内容进行Base64编码,可根据需要处理
  26. var base64EncodeStr=new Buffer(JSON.stringify(responseBody)).toString('base64');
  27. //FC给API网关返回的格式,须如下所示。isBase64Encoded根据body是否Base64编码情况设置
  28. var response = {
  29. isBase64Encoded:true,
  30. statusCode: responseCode,
  31. headers: {
  32. "x-custom-header" : "header value"
  33. },
  34. body: base64EncodeStr
  35. };
  36. console.log("response: " + JSON.stringify(response));
  37. callback(null, response);
  38. };

请求示例

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

  1. /fc/test/invoke/[type]
  1. POST http://test.alicloudapi.com/fc/test/invoke/test?param1=aaa&param2=bbb
  2. "X-Ca-Signature-Headers":"X-Ca-Timestamp,X-Ca-Version,X-Ca-Key,X-Ca-Stage",
  3. "X-Ca-Signature":"TnoBldxxRHrFferGlzzkGcQsaezK+ZzySloKqCOsv2U=",
  4. "X-Ca-Stage":"RELEASE",
  5. "X-Ca-Timestamp":"1496652763510",
  6. "Content-Type":"application/x-www-form-urlencoded; charset=utf-8",
  7. "X-Ca-Version":"1",
  8. "User-Agent":"Apache-HttpClient\/4.1.2 (java 1.6)",
  9. "Host":"test.alicloudapi.com",
  10. "X-Ca-Key":"testKey",
  11. "Date":"Mon, 05 Jun 2017 08:52:43 GMT","Accept":"application/json",
  12. "headerParam":"testHeader"
  13. {"bodyParam":"testBody"}

API 网关返回示例

  1. 200
  2. Date: Mon, 05 Jun 2017 08:52:43 GMT
  3. Content-Type: application/json; charset=UTF-8
  4. Content-Length: 429
  5. Access-Control-Allow-Origin: *
  6. Access-Control-Allow-Methods: GET,POST,PUT,DELETE,HEAD,OPTIONS , PATCH
  7. 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
  8. Access-Control-Max-Age: 172800
  9. X-Ca-Request-Id: 16E9D4B5-3A1C-445A-BEF1-4AD8E31434EC
  10. x-custom-header: header value
  11. {"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 和函数是一对一的关系存在。