在 Node.js 中定義 Lambda 函數處理常式
Lambda 函數處理常式是您的函數程式碼中處理事件的方法。當有人呼叫您的函數時,Lambda 會執行處理常式方法。函數會執行,直到處理常式傳回回應、結束或逾時為止。
本頁介紹了如何在 Node.js 中使用 Lambda 函式處理常式,包括專案設定選項、命名慣例及最佳實務。本頁還提供了一個 Node.js Lambda 函式範例,該函式會取得訂單的相關資訊、產生文字檔案收據,並將該檔案放入 Amazon Simple Storage Service (Amazon S3) 儲存貯體。如需編寫函數後如何部署函數的詳細資訊,請參閱使用 .zip 封存檔部署 Node.js Lambda 函數或使用容器映像部署 Node.js Lambda 函數。
主題
設定 Node.js 處理常式專案
初始化 Node.js Lambda 專案的方法有多種。例如,您可以使用 npm 建立標準的 Node.js 專案,建立 AWS SAM 應用程式,或建立 AWS CDK 應用程式。
使用 npm 建立專案:
npm init
此命令會初始化專案,並產生管理專案中繼資料和相依項的 package.json 檔案。
您的函式程式碼位於 .js 或 .mjs JavaScript 檔案中。在下列範例中,此檔案使用 ES 模組處理常式,因此我們將其命名為 index.mjs。Lambda 同時支援 ES 模組與 CommonJS 處理常式。如需更多詳細資訊,請參閱 將函數處理常式指定為 ES 模組。
一個典型的 Node.js Lambda 函式專案遵循以下一般結構:
/project-root ├── index.mjs — Contains main handler ├── package.json — Project metadata and dependencies ├── package-lock.json — Dependency lock file └── node_modules/ — Installed dependencies
Node.js Lambda 函式程式碼範例
以下 Lambda 函式程式碼範例會取得訂單的相關資訊、產生文字檔案收據,並將該檔案放入 Amazon S3 儲存貯體。
注意
此範例使用了 ES 模組處理常式。Lambda 同時支援 ES 模組與 CommonJS 處理常式。如需更多詳細資訊,請參閱 將函數處理常式指定為 ES 模組。
範例 index.mjs Lambda 函式
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'; // Initialize the S3 client outside the handler for reuse const s3Client = new S3Client(); /** * Lambda handler for processing orders and storing receipts in S3. * @param {Object} event - Input event containing order details * @param {string} event.order_id - The unique identifier for the order * @param {number} event.amount - The order amount * @param {string} event.item - The item purchased * @returns {Promise<string>} Success message */ export const handler = async(event) => { try { // Access environment variables const bucketName = process.env.RECEIPT_BUCKET; if (!bucketName) { throw new Error('RECEIPT_BUCKET environment variable is not set'); } // Create the receipt content and key destination const receiptContent = `OrderID: ${event.order_id}\nAmount: $${event.amount.toFixed(2)}\nItem: ${event.item}`; const key = `receipts/${event.order_id}.txt`; // Upload the receipt to S3 await uploadReceiptToS3(bucketName, key, receiptContent); console.log(`Successfully processed order ${event.order_id} and stored receipt in S3 bucket ${bucketName}`); return 'Success'; } catch (error) { console.error(`Failed to process order: ${error.message}`); throw error; } }; /** * Helper function to upload receipt to S3 * @param {string} bucketName - The S3 bucket name * @param {string} key - The S3 object key * @param {string} receiptContent - The content to upload * @returns {Promise<void>} */ async function uploadReceiptToS3(bucketName, key, receiptContent) { try { const command = new PutObjectCommand({ Bucket: bucketName, Key: key, Body: receiptContent }); await s3Client.send(command); } catch (error) { throw new Error(`Failed to upload receipt to S3: ${error.message}`); } }
此 index.mjs 檔案包含以下程式碼區段:
-
import區塊:此區塊用於納入 Lambda 函式所需的程式碼,例如 AWS SDK 用戶端。 -
const s3Client宣告:此宣告會在處理常式函式外部初始化 Amazon S3 用戶端。Lambda 會於初始化階段執行此程式碼,並且該用戶端會被保留下,在多次調用中重複使用。 -
JSDoc 註解區塊:透過 JSDoc 註釋
定義處理常式的輸入與輸出類型。 -
export const handler:此為 Lambda 調用的主要處理常式函式。部署函式時,請為處理常式屬性指定index.handler。Handler屬性的值由檔案名稱與匯出的處理常式方法名稱組成,兩者以點號分隔。 -
uploadReceiptToS3函式:此為主要處理常式函式所參照的協助程式函式。
若要讓此函式正常運作,其執行角色必須允許 s3:PutObject 動作。此外,請確保定義 RECEIPT_BUCKET 環境變數。成功調用後,Amazon S3 儲存貯體應包含收據檔案。
處理常式命名慣例
設定函式時,處理常式的設定值由檔案名稱與匯出的處理常式方法名稱組成,二者以點號分隔。主控台中建立的函數以及本指南中的範例,預設值都是 index.handler。這表示 handler 方法是透過 index.js 或 index.mjs 檔案匯出的。
如果要在主控台中使用不同檔案名稱或函數處理常式名稱建立函數,您必須編輯預設處理常式名稱。
變更函數處理常式名稱的方式 (主控台)
-
開啟 Lambda 主控台的函數
頁面,然後選擇您的函數。 -
選擇 程式碼 索引標籤。
-
向下捲動至執行時間設定窗格,並選擇編輯。
-
在處理常式中,輸入函數處理常式的新名稱。
-
選擇儲存。
定義和存取輸入事件物件
JSON 是 Lambda 函數最常見的標準輸入格式。在此範例中,函數預期輸入類似以下內容:
{ "order_id": "12345", "amount": 199.99, "item": "Wireless Headphones" }
在 Node.js 中開發 Lambda 函式時,可透過 JSDoc 註釋定義輸入事件的預期結構。在此範例中,我們在處理常式的 JSDoc 註解中定義輸入結構:
/** * Lambda handler for processing orders and storing receipts in S3. * @param {Object} event - Input event containing order details * @param {string} event.order_id - The unique identifier for the order * @param {number} event.amount - The order amount * @param {string} event.item - The item purchased * @returns {Promise<string>} Success message */
在 JSDoc 註解內定義這些類型之後,即可直接在程式碼中存取事件物件的欄位。例如,使用 order_id 可以從原始輸入擷取 event.order_id 的值。
Node.js 函式的有效處理常式模式
建議您使用 async/await 來宣告函式處理常式,而不是使用 callback。async/await 能以簡潔且易讀的方式編寫非同步程式碼,無需使用巢狀回呼或串連承諾。您可以透過非同步/等待模式撰寫讀起來像同步程式碼的程式碼,同時仍維持非同步和非封鎖的特性。
使用 async/await (建議採用)
async 關鍵字會將函數標記為非同步,且 await 關鍵字會暫停函數的執行,直到 Promise 獲得解決為止。處理常式接受下列引數:
-
event:包含傳遞至函式的輸入資料。 -
context:包含有關調用、函式以及執行環境的資訊。如需更多詳細資訊,請參閱 使用 Lambda 內容物件擷取 Node.js 函數資訊。
以下所示為 async/await 模式的有效簽章:
export const handler = async(event)=> { };export const handler = async(event, context)=> { };
注意
使用本機整合式開發環境 (IDE) 或文字編輯器來編寫 TypeScript 函式程式碼。無法在 Lambda 主控台上建立 TypeScript 程式碼。
使用回呼
回呼處理常式必須使用 event、context 與 callback 引數。範例:
export const handler =(event, context, callback)=> { };
回呼函式預期會接收一個 Error 與一個回應物件,其中回應物件必須可進行 JSON 序列化。該函式會一直執行,直至事件迴圈
範例 - 具有 callback 的 HTTP 請求
以下範例函式檢查 URL 及傳回狀態碼給叫用端。
import https from "https"; let url = "https://aws.amazon.com/"; export const handler = (event, context, callback) => { https.get(url, (res) => { callback(null, res.statusCode); }).on("error", (e) => { callback(Error(e)); }); };
在處理常式中使用適用於 JavaScript v3 的 SDK
通常,您會使用 Lambda 函式與其他 AWS 資源互動或對其進行更新。與這些資源互動的最簡單方法便是使用 適用於 JavaScript 的 AWS SDK。所有支援的 Lambda Node.js 執行時期都包含適用於 JavaScript 第 3 版的 SDK。不過,強烈建議將所需的 AWS SDK 用戶端納入部署套件。此舉能在日後 Lambda 執行時期更新時,最大限度實現回溯相容性。僅在無法納入額外套件時 (例如使用 Lambda 主控台程式碼編輯器,或在 AWS CloudFormation 範本中編寫內嵌程式碼時),才依賴執行時期提供的 SDK。
若要將 SDK 相依項新增至函數,請針對您需要的特定 SDK 用戶端使用 npm install 命令。在範例程式碼中,我們使用的是 Amazon S3 用戶端。透過在包含 package.json 檔案的目錄中執行下列命令,即可新增這些相依項:
npm install @aws-sdk/client-s3
在函式程式碼中匯入所需的用戶端與命令,如範例函式所示:
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';
然後,初始化 Amazon S3 用戶端:
const s3Client = new S3Client();
在此範例中,我們在主要處理常式函式外部初始化 Amazon S3 用戶端,以免每次調用函式時都必須初始化該用戶端。初始化 SDK 用戶端之後,即可使用該用戶端對該 AWS 服務發起 API 呼叫。此範例程式碼會呼叫 Amazon S3 PutObject API,如下所示:
const command = new PutObjectCommand({
Bucket: bucketName,
Key: key,
Body: receiptContent
});
存取環境變數
在處理常式程式碼中,您可以使用 process.env 來引用任意環境變數。在此範例中,我們使用下列程式碼行來引用定義的 RECEIPT_BUCKET 環境變數:
// Access environment variables const bucketName = process.env.RECEIPT_BUCKET; if (!bucketName) { throw new Error('RECEIPT_BUCKET environment variable is not set'); }
使用全域狀態
在首次調用函式之前,Lambda 會在初始化階段執行靜態程式碼。在初始化期間建立的資源會在調用間隔期間保留在記憶體中,無需您在每次調用函式時都建立這些資源。
在範例程式碼中,S3 用戶端初始化程式碼位於主要處理常式外部。執行時期會在函式處理第一個事件之前初始化用戶端,且用戶端在所有調用中均可供重複使用。
Node.js Lambda 函數的程式碼最佳實務
建置 Lambda 函式時,請遵循下列準則:
-
區隔 Lambda 處理常式與您的核心邏輯。能允許您製作更多可測單位的函式。
-
控制函數部署套件內的相依性。AWS Lambda 執行環境包含多個程式庫。對於 Node.js 和 Python 執行時期,其中包括 AWS SDK。若要啟用最新的一組功能與安全更新,Lambda 會定期更新這些程式庫。這些更新可能會為您的 Lambda 函數行為帶來細微的變更。若要完全掌控您函式所使用的相依性,請利用部署套件封裝您的所有相依性。
-
最小化依存項目的複雜性。偏好更簡易的框架,其可快速在執行環境啟動時載入。
-
將部署套件最小化至執行時期所必要的套件大小。這能減少您的部署套件被下載與呼叫前解壓縮的時間。
請利用執行環境重新使用來改看函式的效能。在函式處理常式之外初始化 SDK 用戶端和資料庫連線,並在本機快取 /tmp 目錄中的靜態資產。由您函式的相同執行個體處理的後續叫用可以重複使用這些資源。這可藉由減少函數執行時間來節省成本。
若要避免叫用間洩漏潛在資料,請不要使用執行環境來儲存使用者資料、事件,或其他牽涉安全性的資訊。如果您的函式依賴無法存放在處理常式內記憶體中的可變狀態,請考慮為每個使用者建立個別函式或個別函式版本。
使用 Keep-Alive 指令維持持續連線的狀態。Lambda 會隨著時間的推移清除閒置連線。叫用函數時嘗試重複使用閒置連線將導致連線錯誤。若要維護持續連線,請使用與執行階段相關聯的 keep-alive (保持啟用) 指令。如需範例,請參閱在 Node.js 中重複使用 Keep-Alive 的連線。
使用環境變數將操作參數傳遞給您的函數。例如,如果您正在寫入到 Amazon S3 儲存貯體,而非對您正在寫入的儲存貯體名稱進行硬式編碼,請將儲存貯體名稱設定為環境變數。
避免在 Lambda 函數中使用遞迴調用,其中函數會調用自己或啟動可能再次調用函數的程序。這會導致意外的函式呼叫量與升高的成本。若您看到意外的調用數量,當更新程式碼時,請立刻將函數的預留並行設為 0,以調節對函數的所有調用。
請勿在您的 Lambda 函數程式碼中使用未記錄的非公有 API。對於 AWS Lambda 受管執行時間,Lambda 會定期將安全性和函數更新套用至 Lambda 的內部 API。這些內部 API 更新可能是向後不相容的,這會導致意外結果,例如若您的函數依賴於這些非公有 API,則叫用失敗。請參閱 API 參考查看公開可用 API 的清單。
撰寫等冪程式碼。為函數撰寫等冪程式碼可確保採用相同方式來處理重複事件。程式碼應正確驗證事件並正常處理重複的事件。如需詳細資訊,請參閱 How do I make my Lambda function idempotent?