請(qǐng)求處理程序(Handler)
您可以使用Go請(qǐng)求處理程序響應(yīng)接收到的事件并執(zhí)行相應(yīng)的業(yè)務(wù)邏輯。本文介紹Go請(qǐng)求處理程序的相關(guān)概念、結(jié)構(gòu)特點(diǎn)和使用示例。
如您需要通過HTTP觸發(fā)器或自定義域名訪問函數(shù),請(qǐng)先獲取請(qǐng)求結(jié)構(gòu)體再自定義HTTP響應(yīng)。更多信息,請(qǐng)參見HTTP觸發(fā)器調(diào)用函數(shù)。
什么是請(qǐng)求處理程序
FC函數(shù)的請(qǐng)求處理程序,是函數(shù)代碼中處理請(qǐng)求的方法。當(dāng)您的FC函數(shù)被調(diào)用時(shí),函數(shù)計(jì)算會(huì)運(yùn)行您提供的Handler方法處理請(qǐng)求。您可以通過函數(shù)計(jì)算控制臺(tái)的函數(shù)入口配置Handler。
對(duì)Go語言的FC函數(shù)而言,您的請(qǐng)求處理程序被編譯為一個(gè)可執(zhí)行的二進(jìn)制文件。您只需要將FC函數(shù)的請(qǐng)求處理程序配置項(xiàng)設(shè)置為該可執(zhí)行文件的文件名即可。
關(guān)于FC函數(shù)的具體定義和相關(guān)操作,請(qǐng)參見創(chuàng)建事件函數(shù)。
請(qǐng)求處理程序的具體配置均需符合函數(shù)計(jì)算平臺(tái)的配置規(guī)范。配置規(guī)范因請(qǐng)求處理程序類型而異。
使用示例
在Go語言的代碼中,您需要引入官方的SDK庫aliyun/serverless/fc-runtime-go-sdk/fc
,并實(shí)現(xiàn)handler
函數(shù)和main
函數(shù)。示例如下。
package main
import (
"fmt"
"context"
"github.com/aliyun/fc-runtime-go-sdk/fc"
)
type StructEvent struct {
Key string `json:"key"`
}
func HandleRequest(ctx context.Context, event StructEvent) (string, error) {
return fmt.Sprintf("hello, %s!", event.Key), nil
}
func main() {
fc.Start(HandleRequest)
}
傳入的event
參數(shù)是一個(gè)包含key
屬性的JSON字符串,示例如下。
{
"key": "value"
}
具體的示例解析如下:
package main
:在Go語言中,Go應(yīng)用程序都包含一個(gè)名為main
的包。import
:需要引用函數(shù)計(jì)算依賴的包,主要包括以下包:github.com/aliyun/fc-runtime-go-sdk/fc
:函數(shù)計(jì)算Go語言的核心庫。context
:函數(shù)計(jì)算Go語言的Context對(duì)象。
func HandleRequest(ctx context.Context, event StructEvent) (string, error)
:處理請(qǐng)求的方法(即Handler),需包含將要執(zhí)行的代碼,參數(shù)含義如下:ctx context.Context
:為您的FC函數(shù)調(diào)用提供在調(diào)用時(shí)的運(yùn)行上下文信息。更多信息,請(qǐng)參見上下文。event StructEvent
:調(diào)用函數(shù)時(shí)傳入的數(shù)據(jù),可以支持多種類型。string, error
:返回兩個(gè)值,字符串和錯(cuò)誤信息。更多信息,請(qǐng)參見錯(cuò)誤處理。return fmt.Sprintf("Hi,%s !", event.Key), nil
:簡(jiǎn)單地返回hello
信息,其中包含傳入的event
。nil
表示沒有報(bào)錯(cuò)。
func main()
:運(yùn)行FC函數(shù)代碼的入口點(diǎn),Go程序必須包含main
函數(shù)。通過添加代碼fc.Start(HandleRequest)
,您的程序即可運(yùn)行在阿里云函數(shù)計(jì)算平臺(tái)。
Event Handler簽名
下面列舉出了有效的Event Handler簽名,其中InputType
和OutputType
與encoding/json
標(biāo)準(zhǔn)庫兼容。
函數(shù)計(jì)算會(huì)使用json.Unmarshal
方法對(duì)傳入的InputType
進(jìn)行反序列化,以及使用json.Marshal
方法對(duì)返回的OutputType
進(jìn)行序列化。關(guān)于如何反序列化函數(shù)的返回?cái)?shù)據(jù),請(qǐng)參考JSON Unmarshal。
func ()
func () error
func (InputType) error
func () (OutputType, error)
func (InputType) (OutputType, error)
func (context.Context) error
func (context.Context, InputType) error
func (context.Context) (OutputType, error)
func (context.Context, InputType) (OutputType, error)
Handler的使用需遵循以下規(guī)則:
Handler必須是一個(gè)函數(shù)。
Handler支持0~2個(gè)輸入?yún)?shù)。如果有2個(gè)參數(shù),則第一個(gè)參數(shù)必須是
context.Context
。Handler支持0~2個(gè)返回值。如果有1個(gè)返回值,則必須是
error
類型;如果有2個(gè)返回值,則第2個(gè)返回值必須是error
。
函數(shù)的Handler示例代碼:
event-struct.go:
event
為Struct類型的示例代碼。event-string.go:
event
為String類型的示例代碼。event-map.go:
event
為map[string]interface{}
類型的示例代碼。
更多Handler示例,請(qǐng)參見examples。
Context
Context的詳細(xì)使用方法,請(qǐng)參見上下文。
使用HTTP觸發(fā)器調(diào)用函數(shù)
示例代碼
package main
import (
"encoding/base64"
"encoding/json"
"fmt"
"net/http"
"github.com/aliyun/fc-runtime-go-sdk/events"
"github.com/aliyun/fc-runtime-go-sdk/fc"
)
type HTTPTriggerEvent events.HTTPTriggerEvent
type HTTPTriggerResponse events.HTTPTriggerResponse
func (h HTTPTriggerEvent) String() string {
jsonBytes, err := json.MarshalIndent(h, "", " ")
if err != nil {
return ""
}
return string(jsonBytes)
}
func NewHTTPTriggerResponse(statusCode int) *HTTPTriggerResponse {
return &HTTPTriggerResponse{StatusCode: statusCode}
}
func (h *HTTPTriggerResponse) String() string {
jsonBytes, err := json.MarshalIndent(h, "", " ")
if err != nil {
return ""
}
return string(jsonBytes)
}
func (h *HTTPTriggerResponse) WithStatusCode(statusCode int) *HTTPTriggerResponse {
h.StatusCode = statusCode
return h
}
func (h *HTTPTriggerResponse) WithHeaders(headers map[string]string) *HTTPTriggerResponse {
h.Headers = headers
return h
}
func (h *HTTPTriggerResponse) WithIsBase64Encoded(isBase64Encoded bool) *HTTPTriggerResponse {
h.IsBase64Encoded = isBase64Encoded
return h
}
func (h *HTTPTriggerResponse) WithBody(body string) *HTTPTriggerResponse {
h.Body = body
return h
}
func HandleRequest(event HTTPTriggerEvent) (*HTTPTriggerResponse, error) {
fmt.Printf("event: %v\n", event)
if event.Body == nil {
return NewHTTPTriggerResponse(http.StatusBadRequest).
WithBody(fmt.Sprintf("the request did not come from an HTTP Trigger, event: %v", event)), nil
}
reqBody := *event.Body
if event.IsBase64Encoded != nil && *event.IsBase64Encoded {
decodedByte, err := base64.StdEncoding.DecodeString(*event.Body)
if err != nil {
return NewHTTPTriggerResponse(http.StatusBadRequest).
WithBody(fmt.Sprintf("HTTP Trigger body is not base64 encoded, err: %v", err)), nil
}
reqBody = string(decodedByte)
}
return NewHTTPTriggerResponse(http.StatusOK).WithBody(reqBody), nil
}
func main() {
fc.Start(HandleRequest)
}
上述示例從SDK中引入了HTTP觸發(fā)器的請(qǐng)求結(jié)構(gòu)HTTPTriggerEvent,以及響應(yīng)結(jié)構(gòu)HTTPTriggerResponse。關(guān)于HTTP觸發(fā)調(diào)用的請(qǐng)求負(fù)載格式和響應(yīng)負(fù)載格式,請(qǐng)參見HTTP觸發(fā)器調(diào)用函數(shù)。
前提條件
已使用上述示例創(chuàng)建運(yùn)行環(huán)境為Go的函數(shù),并創(chuàng)建HTTP觸發(fā)器。具體操作,請(qǐng)參見創(chuàng)建事件函數(shù)和配置HTTP觸發(fā)器并使用HTTP觸發(fā)。
操作步驟
登錄函數(shù)計(jì)算控制臺(tái),在左側(cè)導(dǎo)航欄,單擊函數(shù)。
在頂部菜單欄,選擇地域,然后在函數(shù)頁面,單擊目標(biāo)函數(shù)。
在函數(shù)詳情頁面,單擊配置頁簽,然后再左側(cè)導(dǎo)航欄,單擊觸發(fā)器,在觸發(fā)器頁面獲取HTTP觸發(fā)器的公網(wǎng)訪問地址。
執(zhí)行以下命令調(diào)用函數(shù)。
curl -i "https://http-trigger-demo.cn-shanghai.fcapp.run" -d "Hello FC!"
重要如果HTTP觸發(fā)器的認(rèn)證方式為無需認(rèn)證,您可以直接使用Postman或Curl工具來調(diào)用函數(shù)。具體操作,請(qǐng)參見本文操作步驟。
如果HTTP觸發(fā)器的認(rèn)證方式為簽名認(rèn)證或JWT認(rèn)證,請(qǐng)使用簽名方式或JWT認(rèn)證方式來調(diào)用函數(shù)。具體操作,請(qǐng)參見認(rèn)證鑒權(quán)。
錯(cuò)誤處理
本示例代碼支持使用HTTP Trigger觸發(fā)器或者自定義域名調(diào)用,如果使用API調(diào)用,但配置的測(cè)試參數(shù)不符合HTTP Trigger請(qǐng)求格式規(guī)范,會(huì)出現(xiàn)報(bào)錯(cuò)。
例如,在控制臺(tái)上調(diào)用,配置請(qǐng)求參數(shù)為"Hello, FC!"
,點(diǎn)擊測(cè)試函數(shù)按鈕,會(huì)出現(xiàn)報(bào)錯(cuò)如下所示。
{
"statusCode": 400,
"body": "the request did not come from an HTTP Trigger, event: {\n \"version\": null,\n \"rawPath\": null,\n \"headers\": null,\n \"queryParameters\": null,\n \"body\": null,\n \"isBase64Encoded\": null,\n \"requestContext\": null\n}"
}
如果想獲取原始的請(qǐng)求事件負(fù)載,可以使用下面示例中的Handler。
// GetRawRequestEvent: obtain the raw request event
func GetRawRequestEvent(event []byte) (*HTTPTriggerResponse, error) {
fmt.Printf("raw event: %s\n", string(event))
return NewHTTPTriggerResponse(http.StatusOK).WithBody(string(event)), nil
}
func main() {
fc.Start(GetRawRequestEvent)
}