すべてのプロダクト
Search
ドキュメントセンター

Function Compute:ハンドラー

最終更新日:Aug 08, 2024

Goハンドラーを使用して、受信したイベントに応答し、対応するビジネスロジックを実行できます。 このトピックでは、Goハンドラーの概念と構造について説明し、例を示します。

説明

HTTPトリガーまたはカスタムドメイン名を使用して関数にアクセスする場合は、HTTP応答を定義する前にリクエスト構造体を取得してください。 詳細については、「HTTPトリガーを使用した関数の呼び出し」をご参照ください。

ハンドラーとは何ですか?

Function Computeの関数のハンドラーは、関数コードでリクエストを処理するために使用されるメソッドです。 関数が呼び出されると、Function Computeは設定したハンドラーを使用してリクエストを処理します。 Function Computeコンソールhandlerパラメーターを指定することで、ハンドラーを設定できます。

Function ComputeのGo関数のハンドラは、実行可能なバイナリファイルにコンパイルされます。 Function Computeの関数のハンドラーを実行可能ファイルの名前に設定するだけです。

Function Computeの関数と関連する操作の詳細については、「イベント関数の作成」をご参照ください。

ハンドラーの設定は、Function Computeの設定仕様に準拠している必要があります。 設定の仕様は、ハンドラーの種類によって異なります。

シナリオ

Goコードでは、公式のSDKライブラリaliyun/serverless/fc-runtime-go-sdk/fcを導入し、ハンドラーmain関数を実装する必要があります。 次のサンプルコードに例を示します。

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

input eventの値は、keyプロパティを含むJSON文字列です。 次のサンプルコードに例を示します。

{
  "key": "value"
} 

パラメーターの説明:

  • パッケージメイン: メインパッケージ。 各Goアプリケーションにはメインパッケージが含まれています。

  • import: Function Computeの依存関係をインポートします。 次の依存関係をインポートする必要があります。

    • github.com/aliyun/fc-runtime-go-sdk/fc: Function ComputeのGoのコアライブラリ

    • context: Function ComputeのGoコンテキストオブジェクト。

  • func HandleRequest(ctx context.Context, event StructEvent) (string, error): 実行するコードを含む必要があるハンドラ。 次の項目は、パラメータについて説明します。

    • ctx context.Context: Function Compute関数のランタイムコンテキスト情報。 詳細は、「コンテキスト」をご参照ください。

    • event StructEvent: 関数が呼び出されたときに渡されるデータ。 複数のデータ型がサポートされています。

    • string, error: 文字列とエラーメッセージを含む戻りメッセージ。 詳細については、「エラー処理」をご参照ください。

    • return fmt.Sprintf("Hi,% s !", event.Key), nil: 入力イベントを含むhello情報を返します。 nilが返された場合、エラーは発生しません。

  • func main(): Function Compute関数のコードを実行するためのエントリポイント。 Goプログラムにはmain関数が含まれている必要があります。 fc.Start(HandleRequest) コードを使用すると、プログラムをAlibaba Cloud Function Computeで実行できます。

イベントハンドラ署名

次の項目には、有効なイベントハンドラ署名が一覧表示されます。 その中で、InputTypeOutputTypeencoding/json標準ライブラリと互換性があります。

Function Computeは、json.Unmarshalメソッドを使用して入力InputTypeを逆シリアル化し、json.Marshalメソッドを使用して返されたOutputTypeをシリアル化します。 関数によって返されるデータを逆シリアル化する方法の詳細については、「JSON Unmarshal」をご参照ください。

  • func ()

  • func () エラー

  • func (InputType) エラー

  • func () (OutputType, error)

  • func (InputType) (OutputType, error)

  • func (context.Context) エラー

  • func (context.Context, InputType) エラー

  • func (context.Context) (OutputType, error)

  • func (context.Context, InputType) (OutputType, error)

次のルールに基づいてハンドラーを使用する必要があります。

  • ハンドラーは関数である必要があります。

  • ハンドラーには、最大2つの入力パラメーターを含めることができます。 ハンドラーに2つの入力パラメーターが含まれている場合、最初の入力パラメーターはcontext.Contextである必要があります。

  • ハンドラーは最大2つの値を返すことができます。 値が1つだけ返される場合、値はerrorタイプを示す必要があります。 2つの値が返された場合、2番目の値はエラーメッセージを示す必要があります。

次のセクションでは、ハンドラーのサンプルコードについて説明します。

  • event-struct.go: eventオブジェクトがSTRUCT型であるハンドラーのサンプルコード。

  • event-string.go: eventオブジェクトがSTRING型であるハンドラーのサンプルコード。

  • event-map.go: eventオブジェクトがmap[string]interface{} 型であるハンドラーのサンプルコード。

他のハンドラーのサンプルコードの詳細については、「examples」をご参照ください。

背景

コンテキストの使用方法の詳細については、「コンテキスト」をご参照ください。

HTTPトリガーを使用して関数を呼び出す

サンプルコード

package main

import (
	"encoding/base64"
	"encoding/json"
	"fmt"
	"net/http"

	"github.com/aliyun/fc-runtime-go-sdk/fc"
)

// HTTPTriggerEvent HTTP Trigger Request Event
type HTTPTriggerEvent struct {
	Version         *string           `json:"version"`
	RawPath         *string           `json:"rawPath"`
	Headers         map[string]string `json:"headers"`
	QueryParameters map[string]string `json:"queryParameters"`
	Body            *string           `json:"body"`
	IsBase64Encoded *bool             `json:"isBase64Encoded"`
	RequestContext  *struct {
		AccountId    string `json:"accountId"`
		DomainName   string `json:"domainName"`
		DomainPrefix string `json:"domainPrefix"`
		RequestId    string `json:"requestId"`
		Time         string `json:"time"`
		TimeEpoch    string `json:"timeEpoch"`
		Http         struct {
			Method    string `json:"method"`
			Path      string `json:"path"`
			Protocol  string `json:"protocol"`
			SourceIp  string `json:"sourceIp"`
			UserAgent string `json:"userAgent"`
		} `json:"http"`
	} `json:"requestContext"`
}

func (h HTTPTriggerEvent) String() string {
	jsonBytes, err := json.MarshalIndent(h, "", "  ")
	if err != nil {
		return ""
	}
	return string(jsonBytes)
}

// HTTPTriggerResponse HTTP Trigger Response struct
type HTTPTriggerResponse struct {
	StatusCode      int               `json:"statusCode"`
	Headers         map[string]string `json:"headers,omitempty"`
	IsBase64Encoded bool              `json:"isBase64Encoded,omitempty"`
	Body            string            `json:"body"`
}

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

上記の例では、HTTPTriggerEventはHTTPトリガーのリクエスト形式を宣言し、HTTPTriggerResponseはHTTPトリガーのレスポンス形式を宣言します。 HTTPトリガーのリクエストペイロードとレスポンスペイロードの形式の詳細については、「HTTPトリガーを使用して関数を呼び出す」をご参照ください。

あなたが始める前に

上記の例を使用して、Goランタイムで関数を作成し、HTTPトリガーを作成します。 詳細については、「イベント関数の作成」および「HTTPリクエストで関数を呼び出すHTTPトリガーの設定」をご参照ください。

手順

  1. Function Computeコンソールにログインします。 左側のナビゲーションウィンドウで、[関数] をクリックします。

  2. 上部のナビゲーションバーで、リージョンを選択します。 [関数] ページで、管理する関数をクリックします。

  3. 機能の詳細ページで、[設定] タブをクリックします。 左側のナビゲーションウィンドウで、[トリガー] をクリックします。 [トリガー] ページで、HTTPトリガーのパブリックエンドポイントを取得します。

  4. 次のコマンドを実行して、関数を呼び出します。

    curl -i "https://http-trigger-demo.cn-shanghai.fcapp.run" -d "Hello FC!"
    重要
    • HTTPトリガーの [認証方法] パラメーターが [認証なし] に設定されている場合、Postmanまたはcurlを使用して関数を呼び出すことができます。 詳細については、「手順」をご参照ください。

    • HTTPトリガーのAuthentication MethodパラメーターがSignature AuthenticationまたはJWT Authenticationに設定されている場合、署名メソッドまたはJWT authenticationメソッドを使用して関数を呼び出すことができます。 詳細については、「認証」をご参照ください。

考えられるエラー

このサンプルコードは、HTTPトリガーまたはカスタムドメイン名を使用して呼び出すことができます。 API操作を使用しているが、設定されたテストパラメーターがHTTPトリガーの要求形式要件に準拠していない場合、エラーが報告されます。

たとえば、リクエストパラメーターを "Hello, FC!" として設定した後、function Computeコンソールで [Test Function] をクリックして関数を呼び出すと、次のエラーメッセージが返されます。

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

元のリクエストイベントのペイロードを取得する場合は、次の例のハンドラーを使用できます。

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