已配置CORS仍报错:Node.js/Express API跨域请求失败排查
问题重现
前端部署在 https://www.linkgrid.site,调用部署在Vercel的Express API(https://linkgrid-api.vercel.app/api/users/create)时,出现CORS预检错误:
Access to XMLHttpRequest at 'https://linkgrid-api.vercel.app/api/users/create' from origin 'https://www.linkgrid.site' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
已完成配置:
- Express中启用
cors中间件,允许包含https://www.linkgrid.site在内的多个源 vercel.json中添加了CORS相关响应头- 前后端均确认部署正确
核心原因分析
当前配置存在两处关键问题:
1. Vercel配置的Origin与请求源不匹配
你的vercel.json中Access-Control-Allow-Origin仅设置为https://linkgrid.site,但实际发起请求的源是https://www.linkgrid.site——带www和不带www属于不同域名,导致Vercel返回的CORS头与请求源不匹配,直接触发预检失败。
2. 双重CORS配置的冲突
同时在Vercel路由层和Express应用层配置CORS,可能导致响应头重复或优先级冲突。比如Vercel先返回了不匹配的Origin头,浏览器直接判定预检失败,不会等待Express返回正确的头。
解决方案
方案一:移除Vercel的CORS配置,让Express完全处理
推荐优先让应用层(Express)处理CORS,避免平台层和应用层的配置冲突:
- 修改
vercel.json,删除routes.headers中的所有CORS相关配置,保留核心路由和构建配置:
{ "version": 2, "builds": [ { "src": "dist/server.js", "use": "@vercel/node", "config": { "includeFiles": ["dist/**"] } } ], "routes": [ { "src": "/(.*)", "dest": "dist/server.js" } ] }
确认Express的
cors中间件配置正确,已包含https://www.linkgrid.site(你的app.ts中已配置,无需修改),同时确保编译后的dist/server.js正确包含这段逻辑(可本地编译后检查js文件内容)。重新部署Vercel后端,确保新配置生效。
方案二:修正Vercel的Origin配置(保留双重配置场景)
如果需要在Vercel层配置CORS,需确保Origin匹配所有允许的源:
- 修改
vercel.json中的Access-Control-Allow-Origin为动态值$origin(Vercel支持的变量,自动匹配请求的Origin),同时保留其他CORS头:
{ "version": 2, "builds": [ { "src": "dist/server.js", "use": "@vercel/node", "config": { "includeFiles": ["dist/**"] } } ], "routes": [ { "src": "/(.*)", "dest": "dist/server.js", "headers": { "Access-Control-Allow-Origin": "$origin", "Access-Control-Allow-Methods": "GET,POST,PUT,DELETE,OPTIONS,PATCH", "Access-Control-Allow-Headers": "X-CSRF-Token, X-Requested-With, Accept, Accept-Version, Content-Length, Content-MD5, Content-Type, Date, X-Api-Version, Authorization", "Access-Control-Allow-Credentials": "true", "Access-Control-Max-Age": "86400" } } ] }
注意:使用$origin时,需确保业务逻辑信任所有请求源,或结合Vercel边缘函数做进一步验证。
额外排查步骤
- 测试预检请求:用curl手动发送OPTIONS请求,查看实际响应头:
curl -X OPTIONS https://linkgrid-api.vercel.app/api/users/create -H "Origin: https://www.linkgrid.site" -v
重点检查响应中是否存在Access-Control-Allow-Origin,且值为https://www.linkgrid.site。
清除Vercel缓存:在Vercel控制台的项目部署页面,点击"Redeploy"并选择"Clear build cache",确保新配置不被缓存影响。
检查Express中间件顺序:确保
cors中间件是第一个被加载的(你的代码中已做到),避免其他中间件(如helmet、limiter)提前拦截请求。
内容的提问来源于stack exchange,提问作者Raphael Elias

