Express.js中POST请求遭CORS策略拦截的解决方法咨询
问题背景
React TypeScript项目通过axios发送POST请求到Express TypeScript后端添加评论时,POST请求被浏览器拦截,报错:
Access to XMLHttpRequest at 'http://localhost:3000/api/products/add-comment/6f1a6b96-6cd2-439c-a648-88b9f287f7d2' from origin 'http://localhost:5173' 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.
GET请求正常,但POST请求失败,核心原因是浏览器发送的OPTIONS预请求未被后端正确处理。
解决方案
1. 移除前端请求中的无效CORS头
Access-Control-Allow-Origin是后端返回给前端的响应头,前端请求里添加这个字段完全无效,反而可能干扰请求逻辑。修改axios请求配置:
export const setNewComment = async ( productId: string, name: string, email: string, body: string, doSuccessNewComment: (data: string) => void, doErrorNewComment: () => void ) => { const config = { method: 'post', url: `http://localhost:3000/api/products/add-comment/${productId}`, headers: { 'Content-Type': 'application/json' // 移除多余的Access-Control-Allow-Origin }, data: { name, email, body } }; try { const response = await axios(config); console.log('Response', response.data); const data: IComment = response.data; doSuccessNewComment(data.id); } catch (e) { console.log('Error: ', (e as Error).message); doErrorNewComment(); } };
2. 后端正确处理OPTIONS预请求
浏览器发送POST这类非简单请求前,会先发送OPTIONS请求验证跨域权限。你的后端只在POST路由里设置CORS头,但OPTIONS请求根本没走到该路由,导致响应缺少CORS头被拦截。
方案一:使用cors中间件(推荐)
安装依赖:
npm install cors npm install -D @types/cors
在Express路由或全局应用中启用cors中间件,它会自动处理OPTIONS请求并返回正确的CORS头:
import cors from 'cors'; // 给productsRouter全局启用CORS productsRouter.use(cors({ origin: 'http://localhost:5173', // 指定允许的前端源,比*更安全 methods: ['GET', 'POST', 'OPTIONS', 'PUT', 'DELETE'] }));
方案二:手动处理OPTIONS请求
如果不想依赖中间件,可以全局或在对应路由下添加OPTIONS请求处理:
// 全局处理所有OPTIONS请求 app.options('*', (req, res) => { res.setHeader("Access-Control-Allow-Origin", "*"); res.setHeader("Access-Control-Allow-Methods", "PUT, POST, GET, DELETE, PATCH, OPTIONS"); res.setHeader("Access-Control-Allow-Headers", "Content-Type"); // 允许前端发送的请求头 res.sendStatus(200); });
3. 修正后端返回数据(可选)
当前后端插入评论后返回的是原始请求体,但前端期望拿到新生成的评论ID。可以修改后端代码返回包含ID的对象:
const commentId = uuidv4(); const values = [[ req.params.id, commentToAdd.name, commentToAdd.email, commentToAdd.body, commentId ]]; await connection.query<OkPacket>("INSERT INTO comments (product_id, name, email, body, comment_id) VALUES ?", [values]); res.status(201); res.send({ ...commentToAdd, id: commentId }); // 返回包含ID的响应数据
内容的提问来源于stack exchange,提问作者Natalia

