全部產品
Search
文件中心

Function Compute:請求處理常式(Handler)

更新時間:Jul 06, 2024

您可以使用Java請求處理常式響應接收到的事件並執行相應的商務邏輯。本文介紹Java請求處理常式的相關概念、結構特點和樣本。

說明

如您需要通過HTTP觸發器或自訂網域名訪問函數,請先擷取請求結構體再自訂HTTP響應。更多資訊,請參見HTTP觸發器調用函數

什麼是請求處理常式

FC函數的請求處理常式,是函數代碼中處理請求的方法。當您的函數被調用時,Function Compute會運行您提供的Handler方法處理請求。

您可以通過Function Compute控制台配置請求處理常式,對於Java語言的函數,您的請求處理常式需配置為[包名].[類名]::[方法名]。例如,您的包名為example,類型為HelloFC,方法名為handleRequest,則請求處理常式可配置為example.HelloFC::handleRequest

請求處理常式的具體配置均需符合Function Compute平台的配置規範。配置規範因請求處理常式類型而異。

處理常式介面

您在使用Java編程時,必須要實現Function Compute提供的介面類,fc-java-core庫為請求處理常式定義了以下兩個介面。

  • StreamRequestHandler

    以流的方式接收輸入的event事件並返回執行結果。您需要從輸入資料流中讀取調用函數時的輸入,處理完成後把函數執行結果寫到輸出資料流中來返回。

  • PojoRequestHandler

    以泛型的方式接收輸入的event事件並返回執行結果。您可以自訂輸入和輸出的類型,但是輸入和輸出的類型必須是POJO類型。

StreamRequestHandler

一個最簡單的StreamRequestHandler樣本如下所示。

package example;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.StreamRequestHandler;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

public class HelloFC implements StreamRequestHandler {

    @Override
    public void handleRequest(InputStream inputStream, OutputStream outputStream, Context context) throws IOException {
        outputStream.write(new String("hello world").getBytes());
    }
}           
  • 包名和類名

    由於Java有包的概念,因此執行方法和其他語言有所不同,需要包含包的資訊。程式碼範例中請求處理常式(handler)為example.HelloFC::handleRequest,其中example標識為包名,HelloFC標識為類名,handleRequest標識為類方法。

    說明

    包名和類名可以是任意的,但是需要與函數配置資訊中的請求處理常式欄位相對應。關於請求處理常式的設定,請參見建立事件函數

  • 實現的介面

    您的代碼中必須要實現Function Compute預定義的介面。上述的程式碼範例中實現了StreamRequestHandler,其中的inputStream參數為調用函數時傳入的資料,outputStream參數用於返回函數的執行結果。

  • Context參數

    Context參數中包含一些函數的運行時資訊(例如RequestId、臨時AccessKey等),其類型是com.aliyun.fc.runtime.Context。具體資訊,請參見上下文

  • 傳回值

    實現StreamRequestHandler介面的函數通過outputStream參數返回執行結果。

  • 引入介面庫

    其中用到的com.aliyun.fc.runtime包的依賴可以通過下文的pom.xml引用。

    <dependency>
        <groupId>com.aliyun.fc.runtime</groupId>
        <artifactId>fc-java-core</artifactId>
        <version>1.4.1</version>
    </dependency>           

    您可以通過Maven倉庫擷取fc-java-core最新的版本號碼。

在建立函數之前,您需要將代碼和其依賴的fc-java-core打包為JAR格式的壓縮包。打包方式,請參見編譯部署程式碼封裝

PojoRequestHandler

一個最簡單的PojoRequestHandler樣本如下所示。SimpleRequest的對象需要支援JSON序列化,例如POJO。

// HelloFC.java
package example;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.PojoRequestHandler;

public class HelloFC implements PojoRequestHandler<SimpleRequest, SimpleResponse> {

    @Override
    public SimpleResponse handleRequest(SimpleRequest request, Context context) {
        String message = "Hello, " + request.getFirstName() + " " + request.getLastName();
        return new SimpleResponse(message);
    }
}            
// SimpleRequest.java
package example;

public class SimpleRequest {
    String firstName;
    String lastName;

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public SimpleRequest() {}
    public SimpleRequest(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}            
// SimpleResponse.java
package example;

public class SimpleResponse {
    String message;

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public SimpleResponse() {}
    public SimpleResponse(String message) {
        this.message = message;
    }
}            

傳入的event參數樣本如下。

{
  "firstName": "FC",
  "lastName": "aliyun"
}            

樣本:使用HTTP觸發器調用函數

範例程式碼

以上範例程式碼中,HTTPTriggerEvent.java聲明了HTTP觸發器的請求格式,HTTPTriggerResponse.java聲明了HTTP觸發器的響應格式,關於HTTP觸發器的請求結構體和響應結構體的詳細格式,請參見HTTP觸發器調用函數

HTTPTriggerEvent.java

package example;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(setterPrefix = "with")
public class HTTPTriggerEvent {
    private String version;
    private String rawPath;
    private Map<String, String> headers;
    private Map<String, String> queryParameters;
    private RequestContext requestContext;

    @JsonProperty("isBase64Encoded")
    private boolean IsBase64Encoded;
    private String body;

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder(setterPrefix = "with")
    public static class RequestContext {
        private String accountId;
        private String domainName;
        private String domainPrefix;
        private HttpInfo http;
        private String requestId;
        private String time;
        private String timeEpoch;

        @Data
        @NoArgsConstructor
        @AllArgsConstructor
        @Builder(setterPrefix = "with")
        public static class HttpInfo {
            private String method;
            private String path;
            private String protocol;
            private String sourceIp;
            private String userAgent;
        }
    }

}

HTTPTriggerResponse.java

package example;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Map;

import com.fasterxml.jackson.annotation.JsonProperty;

@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder(setterPrefix = "with")
public class HTTPTriggerResponse {
    private int statusCode;
    private Map<String, String> headers;

    @JsonProperty("isBase64Encoded")
    private boolean IsBase64Encoded;
    private String body;
}

App.java定義了函數入口類。

App.java

package example;

import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import com.aliyun.fc.runtime.Context;
import com.aliyun.fc.runtime.PojoRequestHandler;

/**
 * HTTP Trigger demo
 *
 */
public class App implements PojoRequestHandler<HTTPTriggerEvent, HTTPTriggerResponse> {

    @Override
    public HTTPTriggerResponse handleRequest(HTTPTriggerEvent request, Context context) {
        context.getLogger().info("Receive HTTP Trigger request: " + request.toString());
        String requestBody = request.getBody();
        if (request.isIsBase64Encoded()) {
            requestBody = new String(java.util.Base64.getDecoder().decode(request.getBody()), StandardCharsets.UTF_8);
        }
        String message = "HTTP Trigger request body: " + requestBody;
        context.getLogger().info(message);
        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "text/plain");
        return HTTPTriggerResponse.builder().withStatusCode(200).withHeaders(headers).withBody(request.getBody())
                .withIsBase64Encoded(request.isIsBase64Encoded()).build();
    }
}

本樣本程式除了引入fc-java-core庫外,還需要引入jackson和lombok兩個庫,可以在Maven的設定檔pom.xml中添加此依賴。

<dependency>
  <groupId>com.fasterxml.jackson.core</groupId>
  <artifactId>jackson-databind</artifactId>
  <version>2.16.1</version>
</dependency>
<dependency>
  <groupId>org.projectlombok</groupId>
  <artifactId>lombok</artifactId>
  <version>1.18.30</version>
</dependency>

前提條件

已使用上述樣本建立運行環境為Java的函數,並建立HTTP觸發器。具體操作,請參見建立事件函數配置HTTP觸發器並使用HTTP觸發

操作步驟

  1. 登入Function Compute控制台,在左側導覽列,單擊函數

  2. 在頂部功能表列,選擇地區,然後在函數頁面,單擊目標函數。

  3. 在函數詳情頁面,單擊觸發器管理頁簽,擷取HTTP觸發器的公網訪問地址。

  4. 在Curl工具執行以下命令,調用函數。

    curl -i "https://dev-jav-test-fc-luiqas****.cn-shanghai.fcapp.run" -d 'hello fc3.0'

    以上命令中,https://dev-jav-test-fc-luiqas****.cn-shanghai.fcapp.run為擷取到的HTTP觸發器公網訪問地址。

    響應結果如下。

    HTTP/1.1 200 OK
    Content-Disposition: attachment
    Content-Length: 11
    Content-Type: application/json
    X-Fc-Request-Id: 1-652503f2-afbfd2b1dc4dd0fcb0230959
    Date: Tue, 10 Oct 2023 07:57:38 GMT
    
    hello fc3.0% 
    重要
    • 如果HTTP觸發器的認證方式無需認證,您可以直接使用Postman或Curl工具來調用函數。具體操作,請參見本文操作步驟

    • 如果HTTP觸發器的認證方式簽名認證JWT認證,請使用簽名方式或JWT認證方式來調用函數。具體操作,請參見認證鑒權

錯誤分析

本範例程式碼支援使用HTTP觸發器或者自訂網域名調用。如果使用API調用,但配置的測試參數不符合HTTP觸發器請求格式規範時,會出現報錯。

例如,在控制台上調用函數,配置請求參數為"Hello, FC!",單擊測試函數,收到的響應如下所示。

{
    "errorType": "com.fasterxml.jackson.databind.exc.MismatchedInputException",
    "errorMessage": "Cannot construct instance of `example.HTTPTriggerEvent` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('Hello, FC!')\n at [Source: (byte[])\"\"Hello, FC!\"\"; line: 1, column: 1]",
    "stackTrace": [
        "com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:63)",
        "com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1588)",
        "com.fasterxml.jackson.databind.DeserializationContext.handleMissingInstantiator(DeserializationContext.java:1213)",
        "com.fasterxml.jackson.databind.deser.std.StdDeserializer._deserializeFromString(StdDeserializer.java:311)",
        "com.fasterxml.jackson.databind.deser.BeanDeserializerBase.deserializeFromString(BeanDeserializerBase.java:1495)",
        "com.fasterxml.jackson.databind.deser.BeanDeserializer._deserializeOther(BeanDeserializer.java:207)",
        "com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:197)",
        "com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)",
        "com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4593)",
        "com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3643)"
    ]
}

樣本程式

Function Compute官方庫包含了使用各種處理常式類型和介面的應用程式範例。每個應用程式範例都包含用於輕鬆編譯部署的方法。例如: