如何解决AWS EC2实例与S3静态网站的跨域请求错误?
1. Nest.js CORS配置未指定合法源
你当前调用app.enableCors()时未传入参数,默认配置未明确允许S3静态网站的域名作为跨域请求的合法源。浏览器同源策略会校验后端返回的Access-Control-Allow-Origin是否匹配请求Origin,不匹配就会触发跨域错误。
解决方法:
修改CORS配置,明确指定你的S3静态网站域名(例如https://your-bucket.s3-website-us-east-1.amazonaws.com):
app.enableCors({ origin: 'https://your-s3-static-domain.com', // 替换为实际S3域名 methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', credentials: true, // 若请求携带Cookie等凭证需开启,否则可省略 });
需允许多个源时,可传入数组:
app.enableCors({ origin: ['https://domain-a.com', 'https://domain-b.com'], methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', });
2. 中间件顺序错误
你先启用CORS再手动添加bodyParser中间件,但Nest.js的CORS中间件需要在bodyParser之前执行,否则OPTIONS预检请求的body解析会干扰CORS的正常响应逻辑。
解决方法:
调整中间件顺序,先添加bodyParser再启用CORS:
async function bootstrap() { const appOptions = { bodyParser: false } const app = await NestFactory.create(AppModule, appOptions) // 先配置bodyParser app.use(bodyParser.json({ limit: '10mb', verify: rawBodyBuffer })) app.use(bodyParser.urlencoded({ limit: '20mb', extended: true, verify: rawBodyBuffer })) // 再启用CORS并指定源 app.enableCors({ origin: 'https://your-s3-static-domain.com', methods: 'GET,HEAD,PUT,PATCH,POST,DELETE', }) app.useWebSocketAdapter(new RedisIoAdapter(app)) app.useGlobalPipes(new ValidationPipe({ transform: true })) app.setGlobalPrefix('api') await app.listen(3000) } bootstrap()
3. EC2安全组未开放目标端口
如果EC2安全组的入站规则未开放3000端口,请求根本无法到达后端,浏览器会 fallback 为跨域错误提示。
解决方法:
- 登录AWS控制台进入EC2实例的安全组配置
- 添加入站规则:类型选「自定义TCP」,端口范围填
3000,源选0.0.0.0/0(生产环境可限制为S3的IP段)
4. 前端请求配置或路径错误
检查前端POST请求的URL是否正确:需包含EC2公网IP/域名+/api前缀(你设置了app.setGlobalPrefix('api')),例如http://ec2-public-ip:3000/api/your-endpoint。
若请求携带Cookie等凭证,后端CORS必须设置credentials: true,且origin不能设为*(浏览器禁止带凭证的请求使用通配符源)。
5. OPTIONS预检请求未被正确响应
浏览器发送POST前会先发OPTIONS预检请求确认跨域权限,若后端未正确响应,就会触发错误。
通过浏览器开发者工具Network面板检查OPTIONS请求:
- 状态码应为200或204
- 响应头需包含
Access-Control-Allow-Origin、Access-Control-Allow-Methods等字段
若OPTIONS请求失败,检查Nest.js是否有拦截OPTIONS请求的中间件或守卫,确保CORS中间件优先处理该请求。
内容的提问来源于stack exchange,提问作者Mykola Tokariev

