资讯详情

资讯详情

POST请求为何发送两次?解析CORS预检机制

1. 为什么POST请求会发送两次这个问题在前端开发面试中经常被问到也是实际项目中常见的现象。当你在浏览器控制台的Network面板中看到同一个POST请求出现了两次时这通常与浏览器的安全机制有关。1.1 CORS预检请求机制现代浏览器在发送某些跨域请求前会先发送一个OPTIONS方法的预检请求(preflight request)。这个机制是跨域资源共享(CORS)规范的一部分目的是确保服务器理解并允许实际的跨域请求。预检请求会在以下情况触发使用了PUT、DELETE、CONNECT、OPTIONS、TRACE、PATCH方法设置了自定义请求头(非简单头部)Content-Type不是application/x-www-form-urlencoded、multipart/form-data或text/plain提示简单请求不会触发预检GET、HEAD、POST(使用上述Content-Type)以及只包含简单头部的请求属于简单请求。1.2 预检请求的工作流程当浏览器检测到需要预检的请求时会按以下顺序执行首先发送OPTIONS请求包含Access-Control-Request-Method告知服务器实际请求将使用的方法Access-Control-Request-Headers告知服务器实际请求将携带的自定义头部Origin请求来源服务器响应OPTIONS请求返回Access-Control-Allow-Methods允许的方法列表Access-Control-Allow-Headers允许的头部列表Access-Control-Max-Age预检结果缓存时间如果预检通过浏览器才会发送实际的POST请求2. 如何识别和调试预检请求2.1 浏览器开发者工具中的表现在Chrome开发者工具的Network面板中预检请求会显示为OPTIONS方法状态码通常是204或200请求头包含Access-Control-Request-*系列头部响应头包含Access-Control-Allow-*系列头部2.2 常见问题排查如果遇到预检问题可以检查以下方面服务器是否正确响应OPTIONS请求Access-Control-Allow-Methods是否包含POSTAccess-Control-Allow-Headers是否包含所有自定义头部Access-Control-Allow-Origin是否正确设置3. 服务器端配置示例3.1 Node.js Express配置const express require(express); const app express(); // 处理OPTIONS预检请求 app.options(/api, (req, res) { res.setHeader(Access-Control-Allow-Origin, *); res.setHeader(Access-Control-Allow-Methods, POST, GET, OPTIONS); res.setHeader(Access-Control-Allow-Headers, Content-Type); res.sendStatus(204); }); // 处理实际POST请求 app.post(/api, (req, res) { res.setHeader(Access-Control-Allow-Origin, *); res.json({ message: Success }); }); app.listen(3000);3.2 Nginx配置示例location /api { if ($request_method OPTIONS) { add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods GET, POST, OPTIONS; add_header Access-Control-Allow-Headers Content-Type; add_header Access-Control-Max-Age 86400; return 204; } add_header Access-Control-Allow-Origin *; proxy_pass http://backend; }4. 性能优化建议虽然预检请求是必要的安全机制但我们可以优化其性能影响设置适当的Access-Control-Max-Age头部让浏览器缓存预检结果尽量使用简单请求避免预检合并自定义请求头减少需要预检的头部数量对于频繁使用的API考虑使用同源策略5. 幂等性考虑由于POST方法本身不是幂等的而OPTIONS是安全的这种两次请求机制不会导致数据不一致。但开发时仍需注意确保POST接口的幂等性设计对于非幂等操作考虑使用PUT方法替代在服务端记录请求ID防止重复处理6. 实际项目中的经验在最近的一个电商项目中我们遇到了上传商品图片时触发预检请求的问题。解决方案是将自定义的X-Request-ID头部改为简单头部设置Access-Control-Max-Age为86400秒(1天)在后端统一处理OPTIONS请求这样优化后同一用户一天内只需要发送一次预检请求显著提升了用户体验。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →