如何在AWS ECS/Fargate上缓存Next.js动态路由SSR页面
在AWS ECS/Fargate上缓存Next.js SSR页面的实现方案
问题背景
我正在AWS上使用ECS/Fargate部署Next.js应用(因需自定义日志与监控,无法使用Amplify)。该应用采用api-routes及带getServerSideProps的动态路由实现服务端渲染(SSR),SSR页面URL示例为:
domain.com/foopage/[id]?powerlevel=10000,代码如下:
// pages/foopage/[id].tsx import React from "react"; import type { GetServerSideProps } from "next"; import Head from "next/head"; export default function FooPage({ id }: Record<string, string>) { return ( <div> <Head> <title>Title</title> </Head> <main> <h1> Say Hi to <a href="https://sample-url.com/id">{id}</a>! </h1> </main> </div> ); } export const getServerSideProps: GetServerSideProps = async (context) => { context.res.setHeader( "Cache-Control", "public, s-maxage=10, stale-while-revalidate=59" ); const { id } = context.query; const response = await fetch( `${process.env.CMS_URL}/api/configurations?id=${id}` ); const jsonResponse = await response.json(); return { props: { id }, }; };
希望缓存这些页面,避免服务器每次都重新生成。已知在Vercel上无需配置即可实现边缘缓存,但因业务要求必须使用AWS,请问在AWS中具体该如何实现?是否可通过Lambda@Edge实现?若可以,对应的Lambda函数示例是什么?
解决方案:CloudFront + Lambda@Edge
可以通过CloudFront(AWS边缘CDN)配合Lambda@Edge实现类似Vercel的边缘缓存效果,具体实现步骤如下:
1. 基础架构配置
- 将CloudFront分发的源(Origin)指向你的ECS/Fargate应用对应的ALB(应用负载均衡器)域名。
- 确认CloudFront允许传递查询参数(默认规则包含,但需后续配合缓存键配置)。
2. Lambda@Edge的核心作用
Lambda@Edge能在CloudFront边缘节点执行代码,主要解决两个问题:
- 强化Next.js返回的
Cache-Control头,确保CloudFront正确识别边缘缓存规则。 - 自定义缓存键,让动态路由参数(如
id)和查询参数(如powerlevel)成为缓存区分依据,避免不同请求共用缓存。
3. Lambda@Edge函数示例
(1)Origin Response触发器函数(修正缓存头)
该函数在CloudFront从源服务器拿到响应后执行,确保缓存规则符合边缘缓存要求:
exports.handler = async (event) => { const response = event.Records[0].cf.response; const headers = response.headers; // 保留Next.js设置的Cache-Control头,缺失则补充默认规则 if (!headers['cache-control']) { headers['cache-control'] = [{ key: 'Cache-Control', value: 'public, s-maxage=10, stale-while-revalidate=59' }]; } // 移除私有缓存标记,确保响应可被CloudFront边缘节点缓存 const cacheControlValue = headers['cache-control'][0].value; if (cacheControlValue.includes('private')) { headers['cache-control'][0].value = cacheControlValue.replace('private', 'public'); } // 添加自定义缓存键标识,便于调试 headers['x-cache-key'] = [{ key: 'X-Cache-Key', value: event.Records[0].cf.request.uri + '?' + (event.Records[0].cf.request.querystring || '') }]; return response; };
(2)Viewer Request触发器函数(自定义缓存键)
如果需要强制CloudFront基于URI和查询参数生成缓存键,确保不同参数的请求缓存独立:
exports.handler = async (event) => { const request = event.Records[0].cf.request; const uri = request.uri; const querystring = request.querystring; // 构建包含URI和查询参数的缓存键标识 request.headers['x-cache-key'] = [{ key: 'X-Cache-Key', value: uri + (querystring ? '?' + querystring : '') }]; return request; };
4. 部署与配置注意事项
- Lambda@Edge函数必须部署在
us-east-1区域,才能关联到CloudFront分发。 - 在CloudFront缓存策略中,需设置基于请求URI和查询参数生成缓存键(或配合Lambda@Edge的自定义逻辑)。
- 测试时可通过CloudFront的
X-Cache响应头验证缓存命中情况(Hit from cloudfront表示命中边缘缓存)。 stale-while-revalidate规则生效逻辑:缓存过期后CloudFront先返回旧内容,后台异步刷新缓存,避免用户等待。
内容的提问来源于stack exchange,提问作者EternalObserver
相关产品推荐
相关产品推荐

