Jamstack这个词近几年在前端圈出现的频率越来越高,它代表的不是某个具体框架,而一种将前端与后端彻底解耦的架构思路:页面在构建阶段预渲染成纯静态文件,部署到CDN上直接分发,动态能力则通过API按需补充。而要把这套架构跑顺,一个靠谱的CDN是绕不开的基础设施。AWS CloudFront作为亚马逊云的全球内容分发网络,配合S3存储,构成了静态站点部署的经典组合。这篇文章就来聊聊这套方案的原理、搭建步骤和常见坑。

Jamstack为什么天然适合静态站点与CDN
先说清楚Jamstack到底改变了什么。传统的动态网站每次请求都要经过服务器渲染:用户访问一个页面,后端查数据库、拼模板、返回HTML,整个过程受服务器算力和地域位置限制。Jamstack则把渲染动作提前到构建阶段,Next.js、Hugo、Astro等框架在构建时就把所有页面生成为静态HTML文件,部署后用户的每次请求本质上只是下载一个文件。
这个转变带来两个直接好处。第一是性能,静态文件可以直接从离用户最近的边缘节点返回,省掉了服务器渲染的时间;第二是安全性和成本,不再需要常驻的Web服务器处理请求,攻击面大幅缩小,流量费用也远低于持续运行计算实例。但前提是这些静态文件必须放在离用户足够近的地方——这正是CloudFront的用武之地。S3存储桶本身是单地域的,比如你把桶建在美东,国内访问延迟会非常明显,而通过CloudFront的全球边缘节点缓存后,用户请求会被路由到最近的节点,响应时间可以从几百毫秒压缩到几十毫秒。
另外值得一提的是,Jamstack的Modern Applications理念强调前后端分离加API驱动,CloudFront除了分发静态文件,还能作为API网关的反向代理,把对/api/*路径的请求转发到Lambda函数或API Gateway,实现一套域名下的统一入口。这种玩法在实际项目中非常常见。
从S3到CloudFront:完整的部署配置流程
基础方案分三步走:先把静态文件上传到S3,然后创建CloudFront分发指向这个桶,最后绑定自定义域名。这里逐步展开。
第一步:准备S3存储桶
需要注意一个细节:如果你打算用CloudFront的Origin Access Control(OAC)来保护源站,S3桶必须保持阻止公开访问的状态,权限完全交给CloudFront管理。这是目前AWS官方推荐的做法,避免桶地址被直接扫到绕过CDN。创建桶的命令如下:
# 创建存储桶并阻止公开访问 aws s3api create-bucket --bucket my-jamstack-site --region us-east-1 aws s3api put-public-access-block \ --bucket my-jamstack-site \ --public-access-block-configuration \ BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true # 构建产物同步到桶 npm run build aws s3 sync ./dist s3://my-jamstack-site --delete
第二步:创建CloudFront分发
控制台里配置项不少,重点关心这几个:源站类型选择S3并启用OAC,查看器协议策略选Redirect HTTP to HTTPS强制跳转,缓存策略可以根据文件类型区分。一个实用的做法是给HTML文件设置短TTL保证内容更新及时,给带哈希后缀的JS、CSS、图片设置长TTL充分利用缓存。用AWS CLI创建的示例:
aws cloudfront create-distribution \ --distribution-config file://distribution-config.json
配置文件中关键的部分大致长这样:
{
"Origins": [{
"Id": "my-s3-origin",
"DomainName": "my-jamstack-site.s3.amazonaws.com",
"S3OriginConfig": {
"OriginAccessIdentity": ""
}
}],
"DefaultCacheBehavior": {
"TargetOriginId": "my-s3-origin",
"ViewerProtocolPolicy": "redirect-to-https",
"CachePolicyId": "658327ea-f89d-4fab-a63d-7e88639e58f6"
},
"Enabled": true
}
创建完成后CloudFront会分配一个类似d1234abcd.cloudfront.net的域名,等部署状态变成Deployed就能直接访问了。首次部署通常需要几分钟到十几分钟。
第三步:绑定自定义域名与HTTPS
生产环境肯定不能用地暖色的cloudfront.net域名。在ACM申请一张证书,注意证书必须在us-east-1区域申请才能用于CloudFront。证书验证通过后,在分发的备用域名字段填上你的域名,选择对应证书即可。DNS侧添加一条CNAME记录指向CloudFront域名,HTTPS就自动生效了。
缓存策略与内容更新的几个关键点
缓存是CDN的核心,也是最容易出问题的地方。很多团队上线后发现改了代码页面没变化,十有八九是缓存策略没理清。CloudFront的缓存行为由缓存策略和源响应头共同决定,这里有几条实践经验。
首先,构建产物一定要用内容哈希命名。现代构建工具默认都会给JS和CSS加上类似app.a1b2c3.js的文件名,这类文件内容变了名字就变,可以放心设置一年的长缓存。HTML入口文件则相反,它引用的哈希文件名在每次构建后都不同,所以HTML本身必须设置Cache-Control: no-cache或者很短的TTL,否则用户拿到的旧HTML会去请求已经不存在的旧资源,出现白屏。
其次,主动刷新用失效机制。等缓存自然过期太慢,CloudFront提供了Invalidation API,可以在部署完成后立即清除指定路径的缓存:
# 部署新版本后刷新HTML缓存 aws cloudfront create-invalidation \ --distribution-id E1234ABCD \ --paths "/*index.html" "/index.html"
注意每月前1000条失效路径是免费的,超出部分收费。如果每次部署都刷新/*全站路径,文件一多很容易超额。更聪明的做法是只刷新入口HTML,让哈希资源靠文件名变化自然更新。
最后聊聊API路径的处理。Jamstack站点的动态接口如果部署在Lambda或API Gateway上,可以在CloudFront里加一条缓存行为,路径模式设为/api/*,源站指向API端点,缓存策略选CachingDisabled,确保动态请求不被缓存。这样前端和API共用一个域名,还省去了跨域配置的麻烦。
与CI/CD集成及常见坑总结
手动敲命令部署只适合验证阶段,正式项目应该接入CI/CD流水线。以GitHub Actions为例,典型流程是安装依赖、执行构建、同步S3、触发失效,整个流水线跑完通常两三分钟:
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci && npm run build
- uses: aws-actions/configure-aws-credentials@v4
with:
aws-access-key-id: ${{ secrets.AWS_KEY }}
aws-secret-access-key: ${{ secrets.AWS_SECRET }}
aws-region: us-east-1
- run: aws s3 sync ./dist s3://my-jamstack-site --delete
- run: aws cloudfront create-invalidation
--distribution-id E1234ABCD --paths "/index.html"
再补充几个高频踩坑点。一是忘了在S3桶策略里给CloudFront的服务主体授权,导致分发返回AccessDenied,排查时直接看CloudFront的源站错误日志能快速定位。二是gzip和brotli压缩,新版缓存策略默认开启了压缩,但如果你自定义了缓存策略却忘了勾选,传输体积会翻好几倍。三是国内访问场景,CloudFront的边缘节点在国内的覆盖有限,如果主要用户在国内,需要评估备案和节点选择问题,必要时考虑其他CDN前置。四是--delete参数配合失效策略,旧文件被删但边缘节点还有缓存时会出现间歇性404,解决办法就是上面强调的:哈希资源靠新文件名接管,永远只失效入口HTML。
整体来看,S3加CloudFront这套组合在成本、性能和运维复杂度之间取得了不错的平衡,小到个人博客大到日活百万的活动页都能撑住。理解了缓存与回源这两条主线,其他配置基本都是在做细节调优。
AWS CloudFrontJamstack静态站点部署修改时间:2026-09-08 06:06:49