

# 使用 Node.js Lambda 函数的层
<a name="nodejs-layers"></a>

使用 [Lambda 层](chapter-layers.md)来打包要在多个函数中重复使用的代码和依赖项。层通常包含库依赖项、[自定义运行时系统](runtimes-custom.md)或配置文件。创建层涉及三个常见步骤：

1. 打包层内容。此步骤需要创建 .zip 文件存档，其中包含要在函数中使用的依赖项。

1. 在 Lambda 中创建层。

1. 将层添加到函数。

**Topics**
+ [打包层内容](#nodejs-layers-package)
+ [在 Lambda 中创建层](#publishing-layer)
+ [将层添加到函数](#nodejs-layer-adding)
+ [示例应用程序](#nodejs-layer-sample-app)

## 打包层内容
<a name="nodejs-layers-package"></a>

要创建层，请将您的包捆绑到满足以下要求的 .zip 文件存档中：
+ 使用计划用于 Lambda 函数的相同 Node.js 版本来构建层。例如，如果您使用 Node.js 24 来构建层，则您的函数应使用 Node.js 24 运行时。
+ 您层的 .zip 文件必须使用以下目录结构之一：
  + `nodejs/node_modules`
  + `nodejs/nodeX/node_modules`（例如，其中 *X* 是您的 Node.js 版本`node22`）

  有关更多信息，请参阅 [每个 Lambda 运行时的层路径](packaging-layers.md#packaging-layers-paths)。
+ 您的层中的包必须与 Linux 兼容。Lambda 函数在 Amazon Linux 上运行。

您可以创建包含使用 `npm` 安装的第三方 Node.js 库（例如 `axios` 或 `lodash`）或者您自己的 JavaScript 模块。

### 第三方依赖项
<a name="nodejs-layers-third-party-dependencies"></a>

**要使用 npm 包创建层**

1. 创建所需的目录结构，并将包直接安装到其中：

   ```
   mkdir -p nodejs
   npm install --prefix nodejs lodash axios
   ```

   此命令是将包直接安装到 `nodejs/node_modules` 目录中，这是 Lambda 所需的结构。
**注意**  
对于具有原生依赖项或二进制组件（例如，[sharp](https://www.npmjs.com/package/sharp) 或 [bcrypt](https://www.npmjs.com/package/bcrypt)）的包，请确保它们与 Lambda Linux 环境以及您的函数[架构](foundation-arch.md)兼容。您可能需要使用 `--platform` 标志：  

   ```
   npm install --prefix nodejs --platform=linux --arch=x64 sharp
   ```
对于更复杂的原生依赖项，您可能需要在与 Lambda 运行时匹配的 Linux 环境中对其进行编译。您可以使用 Docker 来实现这一目的。

1. 压缩层内容：

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip nodejs/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\nodejs -DestinationPath .\layer.zip
   ```

------

   您的 .zip 文件的目录结构应如下所示：

   ```
   nodejs/
   ├── package.json
   ├── package-lock.json
   └── node_modules/
       ├── lodash/
       ├── axios/
       └── (dependencies of the other packages)
   ```
**注意**  
请确保您的 .zip 文件包含位于根级别下的 `nodejs` 目录，且该目录内包含 `node_modules`。此结构旨在确保 Lambda 可以找到并导入您的包。
`nodejs/` 目录中的 `package.json` 和 `package-lock.json` 文件供 npm 用于依赖项管理，但 Lambda 不需要使用这些文件来实现层功能。每个已安装的软件包中已经包含自己的 `package.json` 文件，其中定义了 Lambda 如何导入软件包。

### 自定义 JavaScript 模块
<a name="custom-nodejs-modules"></a>

**使用您自己的代码创建层**

1. 为您的层创建所需的目录结构：

   ```
   mkdir -p nodejs/node_modules/validator
   cd nodejs/node_modules/validator
   ```

1. 为您的自定义模块创建一个 `package.json` 文件，以定义其导入方式：  
**Example nodejs/node\$1modules/validator/package.json**  

   ```
   {
     "name": "validator",
     "version": "1.0.0",
     "type": "module",
     "main": "index.mjs"
   }
   ```

1. 创建您的 JavaScript 模块文件：  
**Example nodejs/node\$1modules/validator/index.mjs**  

   ```
   export function validateOrder(orderData) {
     // Validates an order and returns formatted data
     const requiredFields = ['productId', 'quantity'];
     
     // Check required fields
     const missingFields = requiredFields.filter(field => !(field in orderData));
     if (missingFields.length > 0) {
       throw new Error(`Missing required fields: ${missingFields.join(', ')}`);
     }
     
     // Validate quantity
     const quantity = orderData.quantity;
     if (!Number.isInteger(quantity) || quantity < 1) {
       throw new Error('Quantity must be a positive integer');
     }
     
     // Format and return the validated data
     return {
       productId: String(orderData.productId),
       quantity: quantity,
       shippingPriority: orderData.priority || 'standard'
     };
   }
   
   export function formatResponse(statusCode, body) {
     // Formats the API response
     return {
       statusCode: statusCode,
       body: JSON.stringify(body)
     };
   }
   ```

1. 压缩层内容：

------
#### [ Linux/macOS ]

   ```
   zip -r layer.zip nodejs/
   ```

------
#### [ PowerShell ]

   ```
   Compress-Archive -Path .\nodejs -DestinationPath .\layer.zip
   ```

------

   您的 .zip 文件的目录结构应如下所示：

   ```
   nodejs/              
   └── node_modules/
       └── validator/
           ├── package.json
           └── index.mjs
   ```

1. 在您的函数中导入并使用这些模块。示例：

   ```
   import { validateOrder, formatResponse } from 'validator';
   
   export const handler = async (event) => {
     try {
       // Parse the order data from the event body
       const orderData = JSON.parse(event.body || '{}');
       
       // Validate and format the order
       const validatedOrder = validateOrder(orderData);
       
       return formatResponse(200, {
         message: 'Order validated successfully',
         order: validatedOrder
       });
     } catch (error) {
       if (error instanceof Error && error.message.includes('Missing required fields')) {
         return formatResponse(400, {
           error: error.message
         });
       }
       
       return formatResponse(500, {
         error: 'Internal server error'
       });
     }
   };
   ```

   您可以使用以下[测试事件](testing-functions.md#invoke-with-event)调用函数：

   ```
   {
       "body": "{\"productId\": \"ABC123\", \"quantity\": 2, \"priority\": \"express\"}"
   }
   ```

   预期的回应：

   ```
   {
     "statusCode": 200,
     "body": "{\"message\":\"Order validated successfully\",\"order\":{\"productId\":\"ABC123\",\"quantity\":2,\"shippingPriority\":\"express\"}}"
   }
   ```

## 在 Lambda 中创建层
<a name="publishing-layer"></a>

您可以使用 AWS CLI 或 Lambda 控制台发布层。

------
#### [ AWS CLI ]

运行 [publish-layer-version](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/publish-layer-version.html) AWS CLI 命令以创建 Lambda 层：

```
aws lambda publish-layer-version --layer-name my-layer --zip-file fileb://layer.zip --compatible-runtimes nodejs24.x
```

[兼容的运行时](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)参数是可选的。指定后，Lambda 将使用此参数在 Lambda 控制台中筛选层。

------
#### [ Console ]

**创建层（控制台）**

1. 打开 Lambda 控制台的 [Layers page](https://console.aws.amazon.com/lambda/home#/layers)（层页面）。

1. 选择 **Create layer**（创建层）。

1. 选择**上传 .zip 文件**，然后上传您之前创建的 .zip 存档。

1. （可选）对于**兼容的运行时**，请选择与您用于构建层的 Node.js 版本相对应的 Node.js 运行时。

1. 选择**创建**。

------

## 将层添加到函数
<a name="nodejs-layer-adding"></a>

------
#### [ AWS CLI ]

要将层附加到函数，请运行 [update-function-configuration](https://awscli.amazonaws.com/v2/documentation/api/latest/reference/lambda/update-function-configuration.html) AWS CLI 命令。对于 `--layers` 参数，使用层 ARN。ARN 必须指定版本（例如 `arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1`）。有关更多信息，请参阅 [层和层版本](chapter-layers.md#lambda-layer-versions)。

```
aws lambda update-function-configuration --function-name my-function --cli-binary-format raw-in-base64-out --layers "arn:aws:lambda:us-east-1:123456789012:layer:my-layer:1"
```

如果使用 **cli-binary-format** 版本 2，则 AWS CLI 选项是必需的。要将其设为默认设置，请运行 `aws configure set cli-binary-format raw-in-base64-out`。有关更多信息，请参阅*版本 2 的 AWS Command Line Interface 用户指南*中的 [AWS CLI 支持的全局命令行选项](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-options.html#cli-configure-options-list)。

------
#### [ Console ]

**向函数添加层**

1. 打开 Lamba 控制台的[函数](https://console.aws.amazon.com/lambda/home#/functions)页面。

1. 选择函数。

1. 向下滚动到**层**部分，然后选择**添加层**。

1. 在**选择层**下，选择**自定义层**，然后选择您的层。
**注意**  
如果您在创建层时没有添加[兼容的运行时](https://docs.aws.amazon.com/lambda/latest/api/API_PublishLayerVersion.html#lambda-PublishLayerVersion-request-CompatibleRuntimes)，则您的层将不会在此处列出。您可以改为指定层 ARN。

1. 选择**添加**。

------

## 示例应用程序
<a name="nodejs-layer-sample-app"></a>

有关如何使用 Lambda 层的更多示例，请参阅 AWS Lambda Developer Guide GitHub 存储库中的 [layer-nodejs](https://github.com/awsdocs/aws-lambda-developer-guide/tree/main/sample-apps/layer-nodejs) 示例应用程序。此应用程序中有一个包含 [lodash](https://www.npmjs.com/package/lodash) 库的层。创建层后，即可部署并调用相应的函数来确认层是否按预期运行。