Node.js无法接收POST JSON数据?预检请求跨域校验失败排查
问题原因分析
这个问题的核心是浏览器的跨域预请求(OPTIONS请求)没有被你的Node.js服务器正确处理,而PHP服务器和Postman则避开了这个限制:
- 浏览器同源策略约束:当你从浏览器发送跨域POST请求(且请求头包含
content-type: application/json这类非简单头)时,浏览器会自动先发送一个OPTIONS类型的预请求,用来确认服务器是否允许跨域操作。如果服务器没有正确响应这个预请求,浏览器就会抛出你看到的跨域错误。 - Postman无限制:Postman作为API测试工具,不受浏览器同源策略的约束,它会直接发送POST请求,不会触发预请求流程,因此能正常拿到响应。
- PHP服务器的自动处理:大概率是你的PHP服务器(比如搭配的Apache/Nginx)已经配置了CORS自动处理规则,或者你使用的PHP框架默认拦截并处理了OPTIONS请求,返回了符合要求的跨域头。
你的Node.js代码问题所在
你当前的代码只在POST请求的响应里设置了Access-Control-Allow-Origin头,但完全没有处理OPTIONS预请求。当浏览器发送OPTIONS请求时,服务器没有返回任何允许跨域的头信息,直接导致预请求失败,后续的POST请求也被浏览器拦截。
解决方案
推荐两种解决方式,优先选择第一种,更简洁可靠:
方式一:使用cors中间件(推荐)
Express官方推荐使用cors包来处理跨域问题,它会自动帮你处理OPTIONS预请求和所有跨域头的设置:
- 先安装
cors包:npm install cors - 修改你的Node.js代码:
const express = require('express'); const cors = require('cors'); const app = express(); // 全局启用CORS,所有请求都会自动处理跨域逻辑 app.use(cors()); app.use(express.json()); app.post('/post', function(req, res){ res.send(req.body); }) // 启动服务器监听端口 app.listen(3010, () => { console.log('Server running on port 3010'); })
方式二:手动处理OPTIONS请求
如果你不想额外安装依赖,可以手动处理OPTIONS请求,并在所有请求中设置完整的跨域头:
const express = require('express'); const app = express(); app.use(express.json()); // 处理所有OPTIONS预请求,返回允许跨域的头信息 app.options('*', function(req, res){ res.header('Access-Control-Allow-Origin', '*'); res.header('Access-Control-Allow-Methods', 'GET, POST, OPTIONS'); res.header('Access-Control-Allow-Headers', 'Content-Type'); res.sendStatus(200); }); // 处理POST请求,同时设置跨域头 app.post('/post', function(req, res){ res.header('Access-Control-Allow-Origin', '*'); res.send(req.body); }) app.listen(3010, () => { console.log('Server running on port 3010'); })
前端代码小修正
你的前端AJAX还有个细节问题:直接传对象作为data时,jQuery默认会把它编码成x-www-form-urlencoded格式,但你设置了content-type: application/json,所以需要把数据转成JSON字符串:
function callAjax(){ jQuery.ajax({ method: 'POST', url:'http://localhost:3010/post', headers: { "content-type": "application/json" }, data: JSON.stringify({ email:'fake@mail.com' }), // 转成JSON字符串匹配请求头 success: function(data){ console.log(data); }, error: function(err){ console.log(err); } }); }
这样修改后,你的跨域请求就能正常工作了。
内容的提问来源于stack exchange,提问作者Iftikhar Hussain
相关产品推荐
相关产品推荐

