基于Lambda@Edge实现单CloudFront+单S3 Bucket部署多React应用的问题排查
问题根源分析
你的Lambda@Edge函数现在犯了一个典型的SPA路由错误:它把所有进来的请求,不管是页面请求还是静态资源(CSS/JS/图片)请求,都强制重写到了index.html。这就导致浏览器请求static/css/main.xxx.css时,实际拿到的是index.html的内容,浏览器自然会因为MIME类型不匹配报错——毕竟它期望的是CSS,结果收到的是HTML文本。
解决方案:区分页面路由与静态资源请求
我们需要修改Lambda@Edge函数,让它只对需要SPA路由的请求(比如根路径、没有文件后缀的路径)返回index.html,而对静态资源请求,则保留原资源路径,只是加上对应的环境前缀(dev-test/sandbox-test/prod-test)。
修改后的Lambda@Edge代码
'use strict'; exports.handler = (event, context, callback) => { const cf = event.Records[0].cf; const request = cf.request; const origin = request.origin; const domain = request.headers.host[0].value; // 第一步:确定当前请求对应的环境前缀 let envPrefix = ''; if (domain.includes("dev")) { envPrefix = "/dev-test"; } else if (domain.includes("sandbox")) { envPrefix = "/sandbox-test"; } else { envPrefix = "/prod-test"; } // 第二步:判断请求是页面路由还是静态资源 const uri = request.uri; // 定义静态资源的后缀列表,可根据你的项目需求扩展 const staticExtensions = ['.css', '.js', '.png', '.jpg', '.jpeg', '.gif', '.svg', '.ico', '.json']; const isStaticResource = staticExtensions.some(ext => uri.endsWith(ext)); if (isStaticResource) { // 静态资源请求:给URI加上环境前缀 request.uri = `${envPrefix}${uri}`; } else { // 页面路由请求:返回对应环境的index.html,适配SPA路由 request.uri = `${envPrefix}/index.html`; } // 保持Host头修改,避免S3权限验证问题 request.headers.host[0].value = origin.s3.domainName; return callback(null, request); }
代码逻辑说明
- 环境前缀判断:和你原来的逻辑一致,根据Host头确定要指向的S3文件夹路径
- 静态资源识别:通过检查请求URI的后缀,区分出CSS/JS等静态资源请求
- 请求路由分支:
- 静态资源:直接在原URI前加上环境前缀,比如
/static/css/main.css变成/dev-test/static/css/main.css,确保S3返回正确的资源文件 - 页面路由:不管是根路径
/还是其他SPA路由(比如/about),都返回对应环境的index.html,保证SPA的前端路由能正常工作
- 静态资源:直接在原URI前加上环境前缀,比如
额外检查项
- S3文件路径验证:确认你上传的React构建产物路径正确,比如
dev-test文件夹下确实包含static/、index.html等所有build文件夹内的内容 - CloudFront缓存行为设置:确保你的CloudFront分发的Viewer Request事件已关联这个Lambda@Edge函数,且所有路径(
/*)都触发该函数 - S3 MIME类型检查:S3通常会自动识别上传文件的MIME类型,但如果是批量上传,可确认下CSS/JS文件的Content-Type是否正确(比如CSS是
text/css,JS是application/javascript) - 测试验证:可以用curl命令测试静态资源请求,比如:
查看返回内容是否是CSS代码,而非HTML。curl -H "Host: dev.yourdomain.com" https://your-cloudfront-id.cloudfront.net/static/css/main.xxx.css
内容的提问来源于stack exchange,提问作者Diego Molina
相关产品推荐
相关产品推荐

