AWS
高级
架构

AWS 上的推荐基础设施

OpenNext 不会创建底层基础设施。你可以使用首选工具为应用创建基础设施——SST、AWS CDK、Terraform、Serverless Framework 等。

这是推荐的设置。

架构

以下是每个 AWS 资源的推荐配置。

资源文件

创建一个 S3 存储桶,并将 .open-next/assets 文件夹中的内容上传到存储桶的根目录。例如,文件 .open-next/assets/favicon.ico 应上传到存储桶根目录的 /favicon.ico。如果你需要将文件上传到存储桶内的子文件夹,参考本节

.open-next/assets 文件夹中有两种类型的文件:

哈希文件

这些是文件名中包含哈希组件的文件。哈希文件位于 .open-next/assets/_next 文件夹中,例如 .open-next/assets/_next/static/css/0275f6d90e7ad339.css。当文件内容被修改时,文件名中的哈希值保证会更改。因此,哈希文件应在 CDN 级别和浏览器级别都进行缓存。将哈希文件上传到 S3 时,推荐的缓存控制设置是

public,max-age=31536000,immutable

非哈希文件

.open-next/assets 文件夹中的其他文件是从应用的 public/ 文件夹复制的,例如 .open-next/assets/favicon.ico。当内容被修改时,非哈希文件的文件名可能保持不变。非哈希文件应在 CDN 级别缓存,但不在浏览器级别缓存。当非哈希文件的内容被修改时,部署时应使 CDN 缓存失效。将非哈希文件上传到 S3 时,推荐的缓存控制设置是

public,max-age=0,s-maxage=31536000,must-revalidate

缓存文件

创建一个 S3 存储桶,并将 .open-next/cache 文件夹中的内容上传到存储桶的根目录。如果你需要将文件上传到存储桶内的子文件夹,参考本节

.open-next/cache 文件夹中有两种类型的缓存:

  • 路由缓存:此缓存包括构建期间预渲染的 htmljson 文件。它们用于种子重新验证缓存。
  • Fetch 缓存:此缓存包括 fetch 调用响应,其中可能包含敏感信息。确保这些文件不可公开访问。

重新验证表

创建一个具有以下配置的 DynamoDB 表:

  • 分区键:tag (String)
  • 排序键:path (String)
  • 一个名为 revalidate 的索引,具有以下配置:
    • 分区键:path (String)
    • 排序键:revalidatedAt (Number)

图像优化函数

使用 .open-next/image-optimization-function 文件夹中的代码创建一个 Lambda 函数,处理程序为 index.mjs。此外,确保函数配置如下:

  • 将架构设置为 arm64
  • 设置 BUCKET_NAME 环境变量,值为存储原始图像的 S3 存储桶的名称。
  • 如果资源文件上传到 S3 存储桶中的子文件夹,则设置 BUCKET_KEY_PREFIX 环境变量。值为文件夹的路径。这是可选的。
  • 授予 s3:GetObject 权限。

当使用 Next.js <Image> 组件时,此函数处理图像优化请求。函数捆绑的 sharp (opens in a new tab) 库用于转换图像。该库针对 arm64 架构编译,旨在运行在 AWS Lambda Arm/Graviton2 架构上。了解 AWS Graviton2 处理器提供的更佳性价比。 (opens in a new tab)

请注意,图像优化函数响应 Cache-Control 标头,因此图像将在 CDN 级别和浏览器级别都进行缓存。

Server Lambda 函数

使用 .open-next/server-function 文件夹中的代码创建一个 Lambda 函数,处理程序为 index.mjs。此外,确保函数配置如下:

  • 设置 CACHE_BUCKET_NAME 环境变量,值为存储缓存文件的 S3 存储桶的名称。
  • 如果缓存文件上传到 S3 存储桶中的子文件夹,则设置 CACHE_BUCKET_KEY_PREFIX 环境变量。值为文件夹的路径。这是可选的。
  • 设置 CACHE_BUCKET_REGION 环境变量,值为 S3 存储桶的区域。
  • 设置 REVALIDATION_QUEUE_URL 环境变量,值为重新验证队列的 URL。
  • 设置 REVALIDATION_QUEUE_REGION 环境变量,值为重新验证队列的区域。
  • 设置 CACHE_DYNAMO_TABLE 环境变量,值为重新验证表的名称。
  • 授予 s3:GetObjects3:PutObjects3:ListObjects 权限。
  • 授予 sqs:SendMessage 权限。

此函数处理来自 Next.js 应用的所有其他类型的请求,包括服务器端渲染 (SSR) 请求和 API 请求。OpenNext 以 standalone 模式构建 Next.js 应用。standalone 模式生成一个 .next 文件夹,其中包含处理请求的 NextServer 类,以及一个 node_modules 文件夹,其中包含运行 NextServer 所需的所有依赖项。结构如下:

  .next/                -> NextServer
  node_modules/         -> 依赖项

服务器函数适配器包装了 NextServer 并导出一个支持 Lambda 请求和响应的处理函数。server-function bundle 如下所示:

  .next/                -> NextServer
+ .open-next/
  node_modules/         -> 依赖项
+ index.mjs             -> 服务器函数适配器

Monorepo

在 monorepo 的情况下,构建输出看起来略有不同。例如,如果应用位于 packages/web,则构建输出如下所示:

  packages/
    web/
      .next/            -> NextServer
      node_modules/     -> 来自根 node_modules 的依赖项 (可选)
  node_modules/         -> 来自 package node_modules 的依赖项

在这种情况下,服务器函数适配器需要在 .next/ 旁边的 packages/web 内部创建。这是为了确保适配器可以从两个 node_modules 文件夹导入依赖项。将 Lambda 配置与项目结构耦合并不是一个好的做法,因此我们不会将 Lambda 处理程序设置为 packages/web/index.mjs,而是在 server-function bundle 根目录添加一个包装器 index.mjs 来重新导出适配器。结果结构如下所示:

  packages/
    web/
      .next/                -> NextServer
+     .open-next/
      node_modules/          -> 来自根 node_modules 的依赖项 (可选)
+     index.mjs              -> 服务器函数适配器
  node_modules/              -> 来自 package node_modules 的依赖项
+ index.mjs                  -> 适配器包装器

这确保 Lambda 处理程序保持在 index.mjs

CloudFront 分发

创建一个 CloudFront 分发,并将请求分发到相应的处理程序(行为)。配置了以下行为:

行为请求CloudFront Function
/_next/static/*哈希静态文件-S3 存储桶
/favicon.ico
/my-images/*
查看原因
公共资源-S3 存储桶
/_next/image图像优化-图像优化函数
/_next/data/*数据请求设置 x-forwarded-host
查看原因
服务器函数
/api/*API设置 x-forwarded-host
查看原因
服务器函数
/*捕获所有设置 x-forwarded-host
查看原因。另外 参见此处
服务器函数

在边缘运行

通过将其配置为 Origin Request 上的 Lambda@Edge,服务器函数也可以在边缘位置运行。服务器函数可以接受区域请求事件(API payload 版本 2.0)和边缘请求事件(CloudFront Origin Request payload)。根据 Lambda 事件对象的形状,函数将相应地处理请求。

要配置 CloudFront 分发:

行为请求CloudFront FunctionLambda@Edge
/_next/static/*哈希静态文件--S3 存储桶
/favicon.ico
/my-images/*
查看原因
公共资源--S3 存储桶
/_next/image图像优化--图像优化函数
/_next/data/*数据请求设置 x-forwarded-host
查看原因
服务器函数-
/api/*API设置 x-forwarded-host
查看原因
服务器函数-
/*捕获所有设置 x-forwarded-host
查看原因
服务器函数-

重新验证函数

使用 .open-next/revalidation-function 文件夹中的代码创建一个 Lambda 函数,处理程序为 index.mjs

此外,创建一个 SQS FIFO 队列,并将其设置为该函数的事件源。

此函数轮询队列以获取重新验证消息。收到消息后,函数向指定路由发送 HEAD 请求以进行重新验证。

预热函数

使用 .open-next/warmer-function 文件夹中的代码创建一个 Lambda 函数,处理程序为 index.mjs。确保函数配置如下:

  • 设置 FUNCTION_NAME 环境变量,值为服务器 Lambda 函数的名称。
  • 设置 CONCURRENCY 环境变量,值为要预热的服务器函数数量。
  • 授予 lambda:InvokeFunction 权限以允许预热器调用服务器函数。

此外,创建一个 EventBridge 计划规则,每 5 分钟调用一次预热函数。

阅读更多关于 预热工作原理 的信息。

Dynamo Provider 函数

此函数用于填充重新验证表。它是来自 cdk 的自定义资源处理程序,参见 此处 (opens in a new tab)。确保函数配置如下:

  • 设置 CACHE_DYNAMO_TABLE 环境变量,值为存储重新验证表的 DynamoDB 表的名称。
  • 授予 dynamodb:PutItem 权限以允许函数写入 DynamoDB 表。