本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。
Lambda 函數處理常式是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時,Lambda 會執行處理常式方法。函數會執行,直到處理常式傳回回應、結束或逾時為止。
此頁面說明如何使用 Go 處理 Lambda 函數處理常式,包括專案設定、命名慣例和最佳實務。此頁面也包含 Go Lambda 函數的範例,該函數會取得訂單的相關資訊、產生文字檔案接收,並將此檔案放入 Amazon Simple Storage Service (Amazon S3) 儲存貯體。如需編寫函數後如何部署函數的詳細資訊,請參閱使用 .zip 封存檔部署 Go Lambda 函數或使用容器映像來部署 Go Lambda 函數。
主題
設定 Go 處理常式專案
以 Gogo mod init
命令初始化一個 Go Lambda 函數專案:
go mod init
example-go
此處 example-go
是模組名稱。您可以將其取代為任何值。此命令會初始化專案,並產生列有專案相依項的 go.mod
檔案。
使用 go get
命令將任何外部相依項新增至專案。例如,對於以 Go 編寫的所有 Lambda 函數程式碼,您需要納入 github.com/aws/aws-lambda-go/lambdago get
命令納入此套件:
go get github.com/aws/aws-lambda-go
函數程式碼應該存在於 Go 檔案中。在以下範例中,我們將此檔案命名為 main.go
。在此檔案中,您會在處理常式方法中實作核心函數邏輯,以及呼叫此處理常式的 main()
函數。
範例 Go Lambda 函數程式碼
以下範例 Go Lambda 函數程式碼會取得訂單的相關資訊、產生文字檔案收據,並將此檔案放入 Amazon S3 儲存貯體。
範例 main.go
Lambda 函數
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"os"
"strings"
"github.com/aws/aws-lambda-go/lambda"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
type Order struct {
OrderID string `json:"order_id"`
Amount float64 `json:"amount"`
Item string `json:"item"`
}
var (
s3Client *s3.Client
)
func init() {
// Initialize the S3 client outside of the handler, during the init phase
cfg, err := config.LoadDefaultConfig(context.TODO())
if err != nil {
log.Fatalf("unable to load SDK config, %v", err)
}
s3Client = s3.NewFromConfig(cfg)
}
func uploadReceiptToS3(ctx context.Context, bucketName, key, receiptContent string) error {
_, err := s3Client.PutObject(ctx, &s3.PutObjectInput{
Bucket: &bucketName,
Key: &key,
Body: strings.NewReader(receiptContent),
})
if err != nil {
log.Printf("Failed to upload receipt to S3: %v", err)
return err
}
return nil
}
func handleRequest(ctx context.Context, event json.RawMessage) error {
// Parse the input event
var order Order
if err := json.Unmarshal(event, &order); err != nil {
log.Printf("Failed to unmarshal event: %v", err)
return err
}
// Access environment variables
bucketName := os.Getenv("RECEIPT_BUCKET")
if bucketName == "" {
log.Printf("RECEIPT_BUCKET environment variable is not set")
return fmt.Errorf("missing required environment variable RECEIPT_BUCKET")
}
// Create the receipt content and key destination
receiptContent := fmt.Sprintf("OrderID: %s\nAmount: $%.2f\nItem: %s",
order.OrderID, order.Amount, order.Item)
key := "receipts/" + order.OrderID + ".txt"
// Upload the receipt to S3 using the helper method
if err := uploadReceiptToS3(ctx, bucketName, key, receiptContent); err != nil {
return err
}
log.Printf("Successfully processed order %s and stored receipt in S3 bucket %s", order.OrderID, bucketName)
return nil
}
func main() {
lambda.Start(handleRequest)
}
此 main.go
檔案包含以下程式碼區段:
-
package main
:在 Go 中,包含func main()
函數的套件一律要命名為main
。 -
import
區塊:用於納入 Lambda 函數所需的程式碼。 -
type Order struct {}
區塊:定義此 Go struct 中預期輸入事件的形狀。 -
var ()
區塊:用於定義將在 Lambda 函數中使用的任何全域變數。 -
func init() {}
:在此init()
方法的中包含您希望 Lambda 在初始化階段執行的任何程式碼。 -
func uploadReceiptToS3(...) {}
:這是主要handleRequest
處理常式方法所參考的協助程式方法。 -
func handleRequest(ctx context.Context, event json.RawMessage) error {}
:這是主要處理常式方法,其中包含應用程式的主要邏輯。 -
func main() {}
:這是 Lambda 處理常式的必要進入點。lambda.Start()
方法的引數是主要處理常式方法。
若要讓此函數正常運作,其執行角色必須允許 s3:PutObject
動作。此外,請確保定義 RECEIPT_BUCKET
環境變數。成功調用後,Amazon S3 儲存貯體應包含收據檔案。
處理常式命名慣例
對於以 Go 編寫的 Lambda 函數,處理常式的命名不受限制。在此範例中,處理常式方法的名稱為 handleRequest
。若要參考程式碼中的處理常式值,您可以使用 _HANDLER
環境變數。
對於使用 .zip 部署套件部署的 Go 函數,含有函數程式碼的可執行檔必須命名為 bootstrap
。此外,bootstrap
檔案必須位於 .zip 檔案的根層級。對於使用容器映像部署的 Go 函數,可執行檔的名稱不受限制。
定義和存取輸入事件物件
JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中,函數預期輸入類似以下內容:
{
"order_id": "12345",
"amount": 199.99,
"item": "Wireless Headphones"
}
使用以 Go 編寫的 Lambda 函數時,您可以將預期輸入事件的形狀定義為 Go struct。在此範例中,我們透過定義 struct 來代表 Order
:
type Order struct {
OrderID string `json:"order_id"`
Amount float64 `json:"amount"`
Item string `json:"item"`
}
此 struct 符合預期的輸入形狀。定義 struct 之後,可以撰寫處理常式簽章,該簽章採用與 encoding/json standard library
func handleRequest(ctx context.Context, event json.RawMessage) error {
// Parse the input event
var order Order
if err := json.Unmarshal(event, &order); err != nil {
log.Printf("Failed to unmarshal event: %v", err)
return err
...
}
在此還原序列化操作之後,您可以存取 order
變數的欄位。例如,使用 "order_id"
可以從原始輸入擷取 order.OrderID
的值。
注意
encoding/json
套件只能存取匯出的欄位。若要匯出,事件結構中的欄位名稱必須大寫。
存取和使用 Lambda 內容物件
Lambda 內容物件 包含有關調用、函數以及執行環境的資訊。在此範例中,我們在處理常式簽章中將此變數宣告為 ctx
:
func handleRequest(ctx context.Context, event json.RawMessage) error {
...
}
ctx context.Context
輸入是函數處理常式的一個選用引數。如需可接受處理常式簽章的詳細資訊,請參閱Go 處理常式的有效處理常式簽章。
如果您使用 AWS SDK 呼叫其他 服務,在幾個關鍵區域中需要內容物件。例如,您可以使用內容物件載入正確的 AWS SDK 組態,以正確初始化 SDK 用戶端。如下所示:
// Load AWS SDK configuration using the default credential provider chain
cfg, err := config.LoadDefaultConfig(ctx)
SDK 呼叫本身可能需要內容物件做為輸入。例如,s3Client.PutObject
呼叫接受內容物件做為其第一個引數:
// Upload the receipt to S3
_, err = s3Client.PutObject(ctx, &s3.PutObjectInput{
...
})
除了 AWS SDK 請求之外,您也可以使用內容物件進行函數監控。如需內容物件的詳細資訊,請參閱使用 Lambda 內容物件擷取 Go 函數資訊。
Go 處理常式的有效處理常式簽章
當您以 Go 建置 Lambda 函數處理常式時,會有數個選項,但務必堅守以下規則:
-
處理常式必須是一個函式。
-
處理常式採用 0 到 2 之間的引數。如果有兩個引數,第一個引數必須實作
context.Context
。 -
處理常式傳回 0 到 2 之間的引數。若有單一傳回值,它必須實作
error
。如果有兩個傳回值,第二個值必須實作error
。
下方將列出有效的處理常式簽章。TIn
和 TOut
皆代表與 encoding/json 標準程式庫相容的類型。如需詳細資訊,請參閱 func Unmarshal
-
func ()
-
func () error
-
func () (TOut, error)
-
func (TIn) error
-
func (TIn) (TOut, error)
-
func (context.Context) error
-
func (context.Context) (TOut, error)
-
func (context.Context, TIn) error
-
func (context.Context, TIn) (TOut, error)
在處理常式中使用 適用於 Go 的 AWS SDK v2
通常,您將使用 Lambda 函數與其他 AWS 資源互動或進行更新。連接這些資源的最簡單方法是使用 適用於 Go 的 AWS SDK v2
注意
適用於 Go 的 AWS SDK (v1) 處於維護模式,將於 2025 年 7 月 31 日end-of-support。我們建議您未來僅使用 適用於 Go 的 AWS SDK v2。
若要將 SDK 相依項新增至函數,請針對您需要的特定 SDK 用戶端使用 go get
命令。在前面的範例程式碼中,我們使用了 config
程式庫和 s3
程式庫。請在包含 go.mod
和 main.go
檔案的目錄中執行下列命令,來新增這些相依項:
go get github.com/aws/aws-sdk-go-v2/config
go get github.com/aws/aws-sdk-go-v2/service/s3
然後,在函數的 import 區塊中相應地匯入相依項:
import (
...
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/s3"
)
在處理常式中使用 SDK 時,須對用戶端進行正確設定。最簡單的方法是使用預設憑證提供者鏈。此範例說明了載入此組態的其中一種方式:
// Load AWS SDK configuration using the default credential provider chain
cfg, err := config.LoadDefaultConfig(ctx)
if err != nil {
log.Printf("Failed to load AWS SDK config: %v", err)
return err
}
將此組態載入 cfg
變數後,可以將此變數傳遞至用戶端執行個體。範例程式碼會執行個體化一個 Amazon S3 用戶端,如下所示:
// Create an S3 client
s3Client := s3.NewFromConfig(cfg)
在此範例中,我們在 init()
函數中初始化 Amazon S3 用戶端,以避免每次調用函數時都必須初始化它。問題是,在 init()
函數中,Lambda 無法存取內容物件。為解決此問題,您可以在初始化階段傳遞類似 context.TODO()
這樣的預留位置。稍後,當您使用用戶端進行呼叫時,再傳遞完整的內容物件。在 AWS SDK 用戶端初始化和呼叫中使用內容對此解決方法也有所說明。
設定並初始化 SDK 用戶端之後,您就可以使用它與其他 AWS
服務互動。此範例程式碼會呼叫 Amazon S3 PutObject
API,如下所示:
_, err = s3Client.PutObject(ctx, &s3.PutObjectInput{ Bucket: &bucketName, Key: &key, Body: strings.NewReader(receiptContent), })
存取環境變數
在處理常式程式碼中,您可以使用 os.Getenv()
方法參考任何環境變數。在此範例中,我們使用以下程式碼來參考定義的 RECEIPT_BUCKET
環境變數:
// Access environment variables
bucketName := os.Getenv("RECEIPT_BUCKET")
if bucketName == "" {
log.Printf("RECEIPT_BUCKET environment variable is not set")
return fmt.Errorf("missing required environment variable RECEIPT_BUCKET")
}
使用全域狀態
為了避免每次調用函數時建立新的資源,您可以在處理常式程式碼之外宣告和修改 Lambda 函數的全域變數。您可以在 var
區塊或陳述式中定義這些全域變數。此外,處理常式可能會宣告在初始化階段執行的 init()
函數。init
方法在 中的行為 AWS Lambda 與標準 Go 程式中的行為相同。
Go Lambda 函數的程式碼最佳實務
請遵循下列清單中的準則,在建置 Lambda 函數時使用最佳編碼實務:
-
區隔 Lambda 處理常式與您的核心邏輯。能允許您製作更多可測單位的函式。
-
最小化依存項目的複雜性。偏好更簡易的框架,其可快速在執行環境啟動時載入。
-
將部署套件最小化至執行時期所必要的套件大小。這能減少您的部署套件被下載與呼叫前解壓縮的時間。
-
請利用執行環境重新使用來改看函式的效能。在函式處理常式之外初始化 SDK 用戶端和資料庫連線,並在本機快取
/tmp
目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。若要避免叫用間洩漏潛在資料,請不要使用執行環境來儲存使用者資料、事件,或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態,請考慮為每個使用者建立個別函式或個別函式版本。
-
使用 Keep-Alive 指令維持持續連線的狀態。Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線,請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例,請參閱在 Node.js 中重複使用 Keep-Alive 的連線。
-
使用環境變數將操作參數傳遞給您的函數。例如,如果您正在寫入到 Amazon S3 儲存貯體,而非對您正在寫入的儲存貯體名稱進行硬式編碼,請將儲存貯體名稱設定為環境變數。
-
避免在 Lambda 函數中使用遞迴調用,其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量,當更新程式碼時,請立刻將函數的預留並行設為
0
,以調節對函數的所有調用。 -
請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API。對於 AWS Lambda 受管執行期,Lambda 會定期將安全性和功能更新套用至 Lambda 的內部 APIs。這些內部 API 更新可能是向後不相容的,這會導致意外結果,例如若您的函數依賴於這些非公有 API,則叫用失敗。請參閱 API 參考查看公開可用 API 的清單。
-
撰寫等冪程式碼。為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊,請參閱 How do I make my Lambda function idempotent?
(如何讓 Lambda 函數等冪?)。