定義 Lambda 函數處理常式 TypeScript - AWS Lambda

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

定義 Lambda 函數處理常式 TypeScript

Lambda 函數處理常式是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時,Lambda 會執行處理常式方法。函數會執行,直到處理常式傳回回應、結束或逾時為止。

打字稿處理程序基礎知識

範例 TypeScript 處理器

此範例函式記錄事件物件的內容並傳回日誌的位置。注意下列事項:

  • 在 Lambda 函數中使用這段程式碼之前,您必須先新增 @types/aws-lambda 套件當作開發相依項。此套件包含 Lambda 的類型定義。安裝 @types/aws-lambda 後,import 陳述式 (import ... from 'aws-lambda') 會匯入類型定義。它不會導入aws-lambdaNPM包,這是一個不相關的第三方工具。如需詳細資訊,請參閱儲存庫中的 DefinitelyTyped GitHub aws-lambda

  • 此範例中的處理常式是 ES 模組,必須在 package.json 檔案或透過使用 .mjs 檔案副檔名來進行指定。如需詳細資訊,請參閱將函數處理常式指定為 ES 模組

import { Handler } from 'aws-lambda'; export const handler: Handler = async (event, context) => { console.log('EVENT: \n' + JSON.stringify(event, null, 2)); return context.logStreamName; };

執行程序會將引數傳送至處理常式方法。第一個引數是 event 物件,其中包含來自叫用端的資訊。呼叫程式呼叫 Invoke 時,會將這項資訊傳遞為JSON格式化的字串,而執行階段會將它轉換為物件。當 AWS 服務叫用您的函數時,事件結構會因服務而異。使用時 TypeScript,我們建議對事件物件使用類型註釋。如需詳細資訊,請參閱使用事件物件的類型

第二個引數為 內容物件,其中包含有關呼叫、函式和執行環境的資訊。在上述範例中,該函式從內容物件取得日誌串流的名稱並傳回給叫用端。

您也可以使用回呼引數 (此引數是您在非同步處理常式中呼叫來傳送回應的函數)。建議您使用非同步/等待 (而不是回呼)。非同步/等待改善了可讀性、錯誤處理及效率。如需有關非同步/等待和回呼之間差異的詳細資訊,請參閱 使用回呼

使用 async/await

如果您的程式碼執行非同步任務,請使用非同步/等待模式,以確保處理常式能順利完成執行。非同步/等待是一種在 Node.js 中撰寫非同步程式碼的簡潔可讀模式,無需巢狀回呼或鏈結承諾。您可以透過非同步/等待模式撰寫讀起來像同步程式碼的程式碼,同時仍維持非同步和非封鎖的特性。

async 關鍵字會將函數標記為非同步,且 await 關鍵字會暫停函數的執行,直到 Promise 獲得解決為止。

範例 TypeScript 功能-異步

此範例會使用 fetch (可在 nodejs18.x 執行階段使用)。注意下列事項:

  • 在 Lambda 函數中使用這段程式碼之前,您必須先新增 @types/aws-lambda 套件當作開發相依項。此套件包含 Lambda 的類型定義。安裝 @types/aws-lambda 後,import 陳述式 (import ... from 'aws-lambda') 會匯入類型定義。它不會導入aws-lambdaNPM包,這是一個不相關的第三方工具。如需詳細資訊,請參閱儲存庫中的 DefinitelyTyped GitHub aws-lambda

  • 此範例中的處理常式是 ES 模組,必須在 package.json 檔案或透過使用 .mjs 檔案副檔名來進行指定。如需詳細資訊,請參閱將函數處理常式指定為 ES 模組

import { APIGatewayProxyEvent, APIGatewayProxyResult } from 'aws-lambda'; const url = 'https://aws.amazon.com/'; export const lambdaHandler = async (event: APIGatewayProxyEvent): Promise<APIGatewayProxyResult> => { try { // fetch is available with Node.js 18 const res = await fetch(url); return { statusCode: res.status, body: JSON.stringify({ message: await res.text(), }), }; } catch (err) { console.log(err); return { statusCode: 500, body: JSON.stringify({ message: 'some error happened', }), }; } };

使用回呼

建議您使用 非同步/等待 來宣告函數處理常式,而不是使用回呼。非同步/等待是更好的選擇,以下列出幾項原因:

  • 可讀性: 非同步/等待程式碼比回呼程式碼更容易閱讀和理解,回呼程式碼可能很快就會變得難以理解,並引發回呼地獄。

  • 偵錯和錯誤處理: 回呼型程式碼的偵錯工作難度可能不低。呼叫堆疊可能會變得難以理解,且可能會很容易接受錯誤。您可以透過非同步/等待使用 try/catch 區塊來處理錯誤。

  • 效率: 回呼通常需要在程式碼的不同部分之間進行切換。非同步/等待可以減少切換環境的次數,進而產生更有效率的程式碼。

在處理常式中使用回呼時,函數將繼續執行,直到 事件迴圈 清空或函數逾時為止。直到完成所有的事件迴圈任務,回應才會傳送到叫用端。如果函式逾時,便會傳回錯誤。您可以設定內容,將執行階段設定為立即傳送回應。 callbackWaitsForEmptyEventLoop假的。

回乎函式需要兩個引數,一個 Error 和回應。回應物件必須與 JSON.stringify 相容。

範例 TypeScript 函數與回調

此範例函數會從 Amazon API Gateway 接收事件、記錄事件和內容物件,然後將回應傳回給API閘道。注意下列事項:

  • 在 Lambda 函數中使用這段程式碼之前,您必須先新增 @types/aws-lambda 套件當作開發相依項。此套件包含 Lambda 的類型定義。安裝 @types/aws-lambda 後,import 陳述式 (import ... from 'aws-lambda') 會匯入類型定義。它不會導入aws-lambdaNPM包,這是一個不相關的第三方工具。如需詳細資訊,請參閱儲存庫中的 DefinitelyTyped GitHub aws-lambda

  • 此範例中的處理常式是 ES 模組,必須在 package.json 檔案或透過使用 .mjs 檔案副檔名來進行指定。如需詳細資訊,請參閱將函數處理常式指定為 ES 模組

import { Context, APIGatewayProxyCallback, APIGatewayEvent } from 'aws-lambda'; export const lambdaHandler = (event: APIGatewayEvent, context: Context, callback: APIGatewayProxyCallback): void => { console.log(`Event: ${JSON.stringify(event, null, 2)}`); console.log(`Context: ${JSON.stringify(context, null, 2)}`); callback(null, { statusCode: 200, body: JSON.stringify({ message: 'hello world', }), }); };

使用事件物件的類型

建議您不要使用任何類型的處理常式引數和傳回類型,因為您無法檢查類型。而是使用 sam 本機產生事件 AWS Serverless Application Model CLI命令來產生事件,或使用 @types/aws-lambda 套件中的開放原始碼定義。

使用 sam local generate-event 命令來產生事件
  1. 產生 Amazon Simple Storage Service (Amazon S3) 代理事件。

    sam local generate-event s3 put >> S3PutEvent.json
  2. 使用快速類型公用程式,從 S3 PutEvent .json 檔案產生類型定義。

    npm install -g quicktype quicktype S3PutEvent.json -o S3PutEvent.ts
  3. 在程式碼中使用產生的類型。

    import { S3PutEvent } from './S3PutEvent'; export const lambdaHandler = async (event: S3PutEvent): Promise<void> => { event.Records.map((record) => console.log(record.s3.object.key)); };
使用 @types/aws-lambda 套件中的開放原始碼定義來產生事件
  1. 新增 @types/aws-lambda 套件作為開發相依項。

    npm install -D @types/aws-lambda
  2. 在程式碼中使用類型

    import { S3Event } from "aws-lambda"; export const lambdaHandler = async (event: S3Event): Promise<void> => { event.Records.map((record) => console.log(record.s3.object.key)); };

打字稿 Lambda 函數的代碼最佳實踐

在建置 Lambda 函數時,請遵循下列清單中的準則,以使用最佳程式碼撰寫實務:

  • 區隔 Lambda 處理常式與您的核心邏輯。能允許您製作更多可測單位的函式。在 Node.js 時,看起來會是這個樣子:

    exports.myHandler = function(event, context, callback) { var foo = event.foo; var bar = event.bar; var result = MyLambdaFunction (foo, bar); callback(null, result); } function MyLambdaFunction (foo, bar) { // MyLambdaFunction logic here }
  • 控制函數部署套件內的相依性。 AWS Lambda 執行環境包含許多程式庫。對於 Node.js 和 Python 執行階段,這些執行階段包括. AWS SDKs 若要啟用最新的一組功能與安全更新,Lambda 會定期更新這些程式庫。這些更新可能會為您的 Lambda 函數行為帶來細微的變更。若要完全掌控您函式所使用的相依性,請利用部署套件封裝您的所有相依性。

  • 最小化依存項目的複雜性。偏好更簡易的框架,其可快速在執行環境啟動時載入。

  • 將部署套件最小化至執行時間所必要的套件大小。這能減少您的部署套件被下載與呼叫前解壓縮的時間。

  • 請利用執行環境重新使用來改看函式的效能。初始化函數處理常式之外的SDK用戶端和資料庫連線,並在/tmp目錄本機快取靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。

    若要避免叫用間洩漏潛在資料,請不要使用執行環境來儲存使用者資料、事件,或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態,請考慮為每個使用者建立個別函式或個別函式版本。

  • 使用 Keep-Alive 指令維持持續連線的狀態。Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線,請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例,請參閱在 Node.js 中重複使用 Keep-Alive 的連線

  • 使用環境變數將操作參數傳遞給您的函數。例如,如果您正在寫入到 Amazon S3 儲存貯體,而非對您正在寫入的儲存貯體名稱進行硬式編碼,請將儲存貯體名稱設定為環境變數。

  • 避免在 Lambda 函數中使用遞迴叫用,函數會自行叫用或啟動可能再次叫用函數的程序。這會導致意外的函式呼叫量與升高的成本。如果您看到非預期的叫用量,請在更新程式碼時0立即將保留並行的函數設定為限制函數的所有叫用。

  • 請勿在 Lambda 函數程式碼中使用非公開APIs的非公開文件。對於 AWS Lambda 受管執行階段,Lambda 會定期將安全性和功能更新套用至 Lambda 的內部APIs。這些內部API更新可能向後不兼容,導致意外後果,例如,如果您的函數依賴於這些非公共功能,則會導致調用失敗。APIs如需公開可用的清單,請API參閱參考資料APIs。

  • 撰寫等冪程式碼。為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊,請參閱 How do I make my Lambda function idempotent? (如何讓 Lambda 函數等冪?)。