禁用S3公共访问后,CloudFront访问NextJS静态站子页面异常
解决CloudFront+S3托管NextJS静态站点刷新子页面AccessDenied问题
问题原因
刷新子页面(如https://example.com/another-page)时,CloudFront会直接向S3请求another-page对象,但NextJS静态导出的子页面实际存储为S3中的another-page/index.html。S3找不到对应对象,就返回AccessDenied错误。而页面跳转正常是因为前端路由是客户端侧跳转,未触发真实的源站请求。
解决方案:请求路径重写(推荐用CloudFront函数)
通过CloudFront函数修改请求路径,将子页面请求自动映射到对应的index.html文件,步骤如下:
- 登录AWS控制台,进入CloudFront服务,创建新的CloudFront函数
- 将以下代码粘贴到函数编辑器中:
function handler(event) { const request = event.request; const uri = request.uri; // 处理非文件路径(无后缀)且不以/结尾的请求 if (!uri.includes('.') && !uri.endsWith('/')) { request.uri = `${uri}/index.html`; } // 处理以/结尾的请求 else if (uri.endsWith('/')) { request.uri = `${uri}index.html`; } return request; }
- 发布该函数,然后将其关联到你的CloudFront分发的Viewer Request事件(作用于所有缓存行为)
备选方案:自定义错误响应(地址栏会变更)
如果不想用函数,可配置CloudFront自定义错误响应,将403错误重定向到站点根目录的index.html,由NextJS前端路由接管:
- 进入CloudFront分发的错误响应设置
- 添加自定义错误响应:
- HTTP错误代码:403 Forbidden
- 自定义响应代码:200 OK
- 自定义响应页面路径:
/index.html
- 保存配置后,刷新子页面时会返回根页面,再由前端路由渲染对应内容,但地址栏会保持为根路径,体验不如路径重写方案。
内容的提问来源于stack exchange,提问作者netsrikc
相关产品推荐
相关产品推荐

