无法使用来自 react/axios 的 JSON 发出 POST 请求以恢复服务器

Posted

技术标签:

【中文标题】无法使用来自 react/axios 的 JSON 发出 POST 请求以恢复服务器【英文标题】:Cannot make POST request with JSON from react/axios to restify server 【发布时间】:2018-02-18 02:26:33 【问题描述】:

我有一个这样的 restify 设置:

var restify = require('restify');

const server = restify.createServer();

//server.use(restify.plugins.acceptParser(server.acceptable)); // [1]
server.use(restify.plugins.queryParser());
server.use(restify.plugins.bodyParser());

server.use(function(req, res, next) 
  console.log(req); // <-- Never see the POST from React here
  res.setHeader('Access-Control-Allow-Origin', '*');
  res.setHeader('Access-Control-Allow-Headers', '*');
  res.setHeader('Access-Control-Allow-Methods', '*');
  next();
);

我定义了一堆 GETPOST 路由,到目前为止它工作得非常好。我从一个 android 应用程序、Python 脚本调用服务器,并简单地使用 curl 进行测试。完全没有问题。整洁!

但是,现在我已经使用 React 实现了一个 Web 应用程序,并希望使用 axios 包向 restify API 发出请求。 GET 请求很好,所以我排除了 URL 中的任何拼写错误或类似的东西。

但是像下面这样的 POST 请求不起作用:

var data = "test": "hello";
axios.post("http://.../api/v1/message/question/public/add", data)
  .then(function (response) 
    console.log("Test question sent!");
  )
  .catch(function (error) 
    console.log(error);
  );

当我查看浏览器开发者工具时,我可以看到浏览器正在尝试向该 URL 发出 OPTIONS 请求(而不是 POST)。我认为,根据我的阅读,这是因为浏览器正在发出“预检请求”。问题是我收到405 Method Not Allowed 错误:

Request URL: http://.../api/v1/message/question/public/add
Request method: OPTIONS
Remote address: ...
Status code: 405 Method Not Allowed

Response headers (178 B)    
  Server: restify
  Allow: POST
  Content-Type: application/json
  Content-Length: 62
  Date: Sat, 09 Sep 2017 08:16:32 GMT
  Connection: keep-alive
Request headers (485 B) 
  Host: ...
  User-Agent: Mozilla/5.0 (X11; Ubuntu; Linu…) Gecko/20100101 Firefox/55.0
  Accept: text/html,application/xhtml+xm…plication/xml;q=0.9,*/*;q=0.8
  Accept-Language: en-ZA,en-GB;q=0.8,en-US;q=0.5,en;q=0.3
  Accept-Encoding: gzip, deflate
  Access-Control-Request-Method: POST
  Access-Control-Request-Headers: content-type
  Origin: http://...
  DNT: 1
  Connection: keep-alive

但是为什么呢?我允许所有Access-Control-Allow-Methods 重新调整。一切正常,除了来自POST 请求并且只有当它们来自浏览器(使用 React Web 应用程序)时。我认为是因为OPTIONS 请求,但我不知道如何处理。

顺便说一下JSON.stringify(data)POST 请求可以通过,但 API 需要 Json 而不是字符串。而且由于使用所有其他方式它工作得很好,我不想仅仅为了适应这个问题而更改 restify 代码。

[1] 如果我使用这一行,我会收到以下错误:AssertionError [ERR_ASSERTION]: acceptable ([string]) is required at Object.acceptParser (/home/bob/node_modules/restify/lib/plugins/accept.js:30:12)

【问题讨论】:

【参考方案1】:

又过了几个小时,我终于找到了solution。我已将restify 服务器代码更改如下:

var restify = require("restify");
var corsMiddleware = require('restify-cors-middleware')

var cors = corsMiddleware(
  preflightMaxAge: 5, //Optional
  origins: ['*'],
  allowHeaders: ['API-Token'],
  exposeHeaders: ['API-Token-Expiry']
);


// WITHOUT HTTPS
const server = restify.createServer();

server.pre(cors.preflight);
server.use(cors.actual);
...
(rest is the same as above)

说实话,我不知道它的实际作用。但它正在发挥作用,而且今天已经花费了我太多的精力。我希望它会在某些时候对其他人有所帮助。一切似乎都是来自restify 的近期变化。

【讨论】:

【参考方案2】:

如果您的服务器默认不允许OPTIONS,您可以添加显式处理程序:

server.opts(/\.*/, function (req, res, next) 
    res.send(200);
    next();
);

另一个可能的问题是您不会获得以下标题的预期效果:

res.setHeader('Access-Control-Allow-Headers', '*');
res.setHeader('Access-Control-Allow-Methods', '*');

规范允许使用* 通配符值,但浏览器尚不支持它们。因此,您必须做的是,在这些值中明确指定允许的方法和标头:

res.setHeader('Access-Control-Allow-Headers', 'content-type');
res.setHeader('Access-Control-Allow-Methods', 'POST');

这是因为 CORS 预检 OPTIONS 请求显示的请求标头具有以下内容:

Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://...

这些请求标头表明,浏览器正在询问服务器,在此源上运行的某些代码想要向您的服务器发出 POST 请求,该请求将特定的 Content-Type 添加到请求中。您是否可以接收添加自己的Content-TypePOST 请求?

因此,为了响应该预检OPTIONS 请求,浏览器期望接收一个明确允许POSTAccess-Control-Allow-Methods 响应标头,以及一个明确允许Content-TypeAccess-Control-Allow-Headers 响应标头。

【讨论】:

我找到了解决办法,请看我的回答。我实际上尝试过显式设置而不是通配符,但没有任何效果。 Access-Control-Allow-Methods 中是否有 OPTIONS 没有任何区别。我很快就尝试了您的解决方案。 OPTIONS 请求现在确实返回 200,但没有 POST 跟进。同样,无论我是否使用通配符,都是独立的。我想我仍然缺少一些东西。 您的回复肯定是朝着正确的方向发展的,我发现您最后的外行解释非常有用——这与我的背景相去甚远。因此我投赞成票。非常感谢!

以上是关于无法使用来自 react/axios 的 JSON 发出 POST 请求以恢复服务器的主要内容,如果未能解决你的问题,请参考以下文章

PHP Session ID / Session 变量值随着来自 react axios / ajax 调用的每个请求而变化

在 Heroku 上使用 React、Axios 访问内部 API

react-hook-form axios post - 无法创建有效负载

react axios 配置

react axios的二次封装

react axios 跨域问题