Function Compute支援API Gateway作為事件來源,即支援將Function Compute設定為API的後端服務。當請求設定後端服務為Function Compute時,API Gateway會觸發關聯的函數執行一次,Function Compute將執行結果返回給API Gateway。本文介紹在Function Compute控制台配置API Gateway觸發函數執行的流程,包括配置函數的入口參數、編寫函數代碼並測試等。
前提條件
- Function Compute
- API Gateway
步驟一:配置函數的入口參數
API Gateway觸發函數執行時,API Gateway的資訊以event的形式作為輸入參數傳給函數,您可以將API Gateway傳入的event資訊作為參數,調試函數代碼編寫是否正確。
- 在函數詳情頁面,單擊函數代碼頁簽,然後單擊測試函數右側表徵圖,從下拉式清單中,選擇配置測試參數。
- 在配置測試參數面板,選擇建立新測試事件或編輯已有測試事件頁簽,填寫事件名稱和事件內容。然後單擊確定。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 Gateway傳給Function Compute的body內容已進行Base64編碼。Function Compute需要先對body內容進行Base64解碼後再處理。 - 如果
isBase64Encoded
的值為false
,表示API Gateway沒有對body內容進行Base64編碼,在函數中可以直接擷取body內容。
- 如果
步驟二:編寫函數代碼並測試
- 在左側導覽列,單擊服務及函數。
在頂部功能表列,選擇地區。
在服務列表頁面,找到目標服務,在其右側操作列單擊函數管理。
在函數管理頁面,單擊目標函數名稱。
- 在函數詳情頁面,單擊函數代碼頁簽,在代碼編輯器中編寫代碼,然後單擊部署代碼。不同語言的範例程式碼如下:
- Node.js
module.exports.handler = function(event, context, callback) { var event = JSON.parse(event); var content = { path: event.path, method: event.method, headers: event.headers, queryParameters: event.queryParameters, pathParameters: event.pathParameters, body: event.body // 您可以在這裡編寫您自己的邏輯。 } var response = { isBase64Encoded: false, statusCode: '200', headers: { 'x-custom-header': 'header value' }, body: content }; callback(null, response) };
- Python
# -*- coding: utf-8 -*- import json def handler(event, context): event = json.loads(event) content = { 'path': event['path'], 'method': event['httpMethod'], 'headers': event['headers'], 'queryParameters': event['queryParameters'], 'pathParameters': event['pathParameters'], 'body': event['body'] } # 您可以在這裡編寫您自己的邏輯。 rep = { "isBase64Encoded": "false", "statusCode": "200", "headers": { "x-custom-header": "no" }, "body": content } return json.dumps(rep)
- PHP
<?php function handler($event, $context) { $event = json_decode($event, $assoc = true); $content = [ 'path' => $event['path'], 'method' => $event['httpMethod'], 'headers' => $event['headers'], 'queryParameters' => $event['queryParameters'], 'pathParameters' => $event['pathParameters'], 'body' => $event['body'], ]; $rep = [ "isBase64Encoded" => "false", "statusCode" => "200", "headers" => [ "x-custom-header" => "no", ], "body" => $content, ]; return json_encode($rep); }
- Java
使用Java編程時,必須要實現一個類,需要實現Function Compute預定義的handler,目前有兩個預定義的handler可以實現(任選其一即可)。Function ComputeJava運行環境,請參見編譯部署程式碼封裝。
- (推薦)使用PojoRequestHandler<I, O> handler。
import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.PojoRequestHandler; import java.util.HashMap; import java.util.Map; public class ApiTriggerDemo implements PojoRequestHandler<ApiRequest, ApiResponse> { public ApiResponse handleRequest(ApiRequest request, Context context) { // 擷取API請求資訊。 context.getLogger().info(request.toString()); String path = request.getPath(); String httpMethod = request.getHttpMethod(); String body = request.getBody(); context.getLogger().info("path:" + path); context.getLogger().info("httpMethod:" + httpMethod); context.getLogger().info("body:" + body); // 您可以在這裡編寫您自己的邏輯。 // API返回樣本。 Map headers = new HashMap(); boolean isBase64Encoded = false; int statusCode = 200; String returnBody = ""; return new ApiResponse(headers,isBase64Encoded,statusCode,returnBody); } }
- 兩個
POJO
類、ApiRequest
類和ApiResponse
類定義如下。說明POJO
類的set()
和get()
方法要寫全。import java.util.Map; public class ApiRequest { private String path; private String httpMethod; private Map headers; private Map queryParameters; private Map pathParameters; private String body; private boolean isBase64Encoded; @Override public String toString() { return "Request{" + "path='" + path + '\'' + ", httpMethod='" + httpMethod + '\'' + ", headers=" + headers + ", queryParameters=" + queryParameters + ", pathParameters=" + pathParameters + ", body='" + body + '\'' + ", isBase64Encoded=" + isBase64Encoded + '}'; } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public String getHttpMethod() { return httpMethod; } public void setHttpMethod(String httpMethod) { this.httpMethod = httpMethod; } public Map getHeaders() { return headers; } public void setHeaders(Map headers) { this.headers = headers; } public Map getQueryParameters() { return queryParameters; } public void setQueryParameters(Map queryParameters) { this.queryParameters = queryParameters; } public Map getPathParameters() { return pathParameters; } public void setPathParameters(Map pathParameters) { this.pathParameters = pathParameters; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } public boolean getIsBase64Encoded() { return this.isBase64Encoded; } public void setIsBase64Encoded(boolean base64Encoded) { this.isBase64Encoded = base64Encoded; } }
import java.util.Map; public class ApiResponse { private Map headers; private boolean isBase64Encoded; private int statusCode; private String body; public ApiResponse(Map headers, boolean isBase64Encoded, int statusCode, String body) { this.headers = headers; this.isBase64Encoded = isBase64Encoded; this.statusCode = statusCode; this.body = body; } public Map getHeaders() { return headers; } public void setHeaders(Map headers) { this.headers = headers; } public boolean getIsBase64Encoded() { return isBase64Encoded; } public void setIsBase64Encoded(boolean base64Encoded) { this.isBase64Encoded = base64Encoded; } public int getStatusCode() { return statusCode; } public void setStatusCode(int statusCode) { this.statusCode = statusCode; } public String getBody() { return body; } public void setBody(String body) { this.body = body; } }
- pom.xml檔案如下。
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>apiTrigger</groupId> <artifactId>apiTrigger</artifactId> <version>1.0-SNAPSHOT</version> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>com.aliyun.fc.runtime</groupId> <artifactId>fc-java-core</artifactId> <version>1.0.0</version> </dependency> </dependencies> </project>
- 使用StreamRequestHandler handler。
使用該handler,需要將輸入的
InputStream
轉換為對應的POJO
類,範例程式碼如下。pom.xml檔案配置與使用PojoRequestHandler<I, O> handler相同。
import com.aliyun.fc.runtime.Context; import com.aliyun.fc.runtime.StreamRequestHandler; import com.aliyun.fc.runtime.Context; import com.google.gson.Gson; import java.io.*; import java.util.Base64; import java.util.HashMap; import java.util.Map; public class ApiTriggerDemo2 implements StreamRequestHandler { public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) { try { // 將InputStream轉化成字串。 BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); StringBuffer stringBuffer = new StringBuffer(); String string = ""; while ((string = bufferedReader.readLine()) != null) { stringBuffer.append(string); } String input = stringBuffer.toString(); context.getLogger().info("inputStream: " + input); Request req = new Gson().fromJson(input, Request.class); context.getLogger().info("input req: "); context.getLogger().info(req.toString()); String bodyReq = req.getBody(); Base64.Decoder decoder = Base64.getDecoder(); context.getLogger().info("body: " + new String(decoder.decode(bodyReq))); // 您可以在這裡處理您自己的邏輯。 // 返回結構。 Map headers = new HashMap(); headers.put("x-custom-header", " "); boolean isBase64Encoded = false; int statusCode = 200; Map body = new HashMap(); Response resp = new Response(headers, isBase64Encoded, statusCode, body); String respJson = new Gson().toJson(resp); context.getLogger().info("outputStream: " + respJson); outputStream.write(respJson.getBytes()); } catch (IOException e) { e.printStackTrace(); } finally { try { outputStream.close(); inputStream.close(); } catch (IOException e) { e.printStackTrace(); } } } class Request { private String path; private String httpMethod; private Map headers; private Map queryParameters; private Map pathParameters; private String body; private boolean isBase64Encoded; @Override public String toString() { return "Request{" + "path='" + path + '\'' + ", httpMethod='" + httpMethod + '\'' + ", headers=" + headers + ", queryParameters=" + queryParameters + ", pathParameters=" + pathParameters + ", body='" + body + '\'' + ", isBase64Encoded=" + isBase64Encoded + '}'; } public String getBody() { return body; } } // Function Compute需要以以下JSON格式返回對API Gateway的響應。 class Response { private Map headers; private boolean isBase64Encoded; private int statusCode; private Map body; public Response(Map headers, boolean isBase64Encoded, int statusCode, Map body) { this.headers = headers; this.isBase64Encoded = isBase64Encoded; this.statusCode = statusCode; this.body = body; } } }
- (推薦)使用PojoRequestHandler<I, O> handler。
- Node.js
- 單擊函數代碼頁簽的測試函數。
步驟三:驗證結果
執行完成後,您可以在函數代碼頁簽的上方查看執行結果。
{
"isBase64Encoded":true|false,
"statusCode":httpStatusCode,
"headers":{response headers},
"body":"..."
}
- 如果Function Compute返回給API Gateway的結果不符合格式要求,API Gateway會返回503 Service Unavailable。
- 當body內容為二進位時,需對其進行Base64編碼,即isBase64Encoded設定為true;當body內容為非二進位時,無需對其進行Base64編碼,即isBase64Encoded設定為false。
常見問題
API Gateway觸發函數執行時報503,查看函數日誌,函數已經執行成功了,這是怎麼回事?
API Gateway和Function Compute的對接有格式要求,如果Function Compute返回給API Gateway的結果沒有按規定的格式返回,那麼API Gateway就認為後端服務不可用。關於API Gateway和Function Compute的對接格式要求,請參見觸發器Event格式和Function Compute的返回參數格式。
如何設定返迴響應的content-type?
API Gateway觸發Function Compute執行,已經調通的函數,一段時間不調用,再次調用會報503,這是什麼原因?
一段時間不調用後,函數重新調用需要準備執行環境,有冷啟動時延,在API Gateway設定的逾時時間內沒有調用完,API Gateway會認為後端服務不可用。延長API Gateway的逾時時間即可解決問題。
為什麼函數中接收到API Gateway傳過來的body是經過了Base64編碼的?
API Gateway對FORM形式的body傳輸是不進行Base64編碼的(使用FORM形式需要在API Gateway選擇入參映射),其他形式body都會進行Base64編碼,避免內容傳輸錯誤或者丟失。建議您在使用時,先判斷event中isBase64是否為true。如果isBase64為true,則body需要在函數中進行解碼。關於API Gateway傳給Function Compute的event格式,請參見觸發器Event格式。
更多資訊
除了Function Compute控制台,您還可通過以下方式配置觸發器:
通過Serverless Devs工具配置觸發器。更多操作,請參見Serverless Devs。
通過SDK配置觸發器。更多操作,請參見SDK列表。
如需對建立的觸發器進行修改或刪除,請參見觸發器管理。