Restify POST接口错误数据无法在客户端JavaScript中显示的问题
兄弟,你遇到的问题本质还是**跨域资源共享(CORS)**的问题——别以为localhost就不存在跨域,浏览器的同源策略卡的是「协议+域名+端口」三者完全一致,哪怕你的前端页面跑在localhost:8080,后端在localhost:3979,这俩就是不同源的。curl不受浏览器同源策略限制,所以能正常拿到响应,但浏览器会拦截跨域的错误响应,导致你在fail()里拿不到任何有效数据。
下面是具体的解决步骤:
1. 给Restify配置CORS中间件
Restify默认的CORS支持不够完善,建议用专门的restify-cors-middleware插件来处理:
首先安装插件:
npm install restify-cors-middleware --save
2. 修改服务器端代码,添加CORS配置
更新你的Node.js代码,在创建服务器后立即配置CORS中间件,确保预检请求(OPTIONS)能被正确响应,同时允许浏览器读取错误响应的内容:
const restify = require('restify'); const corsMiddleware = require('restify-cors-middleware'); // 配置CORS规则,根据你的实际情况调整origin const cors = corsMiddleware({ origins: ['http://localhost:你的前端端口'], // 比如你的前端跑在8080就填这个,或者用['*']允许所有(生产环境不建议) allowHeaders: ['Content-Type'], exposeHeaders: ['Content-Type'] }); // 创建服务器 let server = restify.createServer(); // 先使用CORS中间件处理请求 server.pre(cors.preflight); server.use(cors.actual); // 解析请求体(处理POST的JSON数据) server.use(restify.plugins.bodyParser()); server.listen(process.env.port || process.env.PORT || 3979, function () { console.log(`${server.name} listening to ${server.url}`); }); // POST接口修改:确保响应头正确,也可以用Restify内置的错误类 server.post("/api/address", async (req, res) => { // 方式1:直接发送错误响应 res.status(400); res.setHeader('Content-Type', 'application/json'); res.send({errorMessage: "The value given does not appear to be valid."}); // 方式2:用Restify内置的BadRequestError(更规范) // return new restify.errors.BadRequestError("The value given does not appear to be valid."); });
3. 调整前端jQuery代码(可选但推荐)
你的前端AJAX请求没有指定contentType,默认会以application/x-www-form-urlencoded发送数据,Restify需要用bodyParser解析这种格式,不过更推荐发送JSON格式:
function doPost() { $.ajax({ url: "http://localhost:3979/api/address", type: "POST", contentType: "application/json", // 指定发送JSON格式 // Request body. data: JSON.stringify({key: "mykey", address: "myaddress"}) // 转成JSON字符串 }) .done(function(data) { $("#outputTextArea").val(JSON.stringify(data, null, 2)); }) .fail(function(jqXHR, textStatus, errorThrown) { $("#outputTextArea").val( "status: " + jqXHR.status + ", textStatus: " + textStatus + ", errorThrown: " + errorThrown + "\r\nresponse: " + jqXHR.responseText ); }); }
为什么之前的代码不行?
当浏览器发起跨域POST请求时,会先发送一个OPTIONS预检请求,询问服务器是否允许该跨域请求。如果服务器没有正确响应OPTIONS请求(比如没有返回允许的Origin、Headers等),浏览器就会直接拦截后续的响应,不会把响应内容交给JavaScript,这就是你看到jqXHR.status=0、responseText为空的原因。而curl不会做这些预检,所以能正常拿到数据。
配置CORS中间件后,服务器会正确处理OPTIONS请求,同时在响应中添加Access-Control-Allow-Origin等头信息,浏览器就会允许JavaScript读取错误响应的内容了。
内容的提问来源于stack exchange,提问作者Roy Harper

