(浏览器作为客户端)$.ajax 上的 HTTP 405 POST 到节点服务

Posted

技术标签:

【中文标题】(浏览器作为客户端)$.ajax 上的 HTTP 405 POST 到节点服务【英文标题】:(Browser-as-Client) HTTP 405 on $.ajax POST to a Node service 【发布时间】:2015-02-18 22:15:39 【问题描述】:

背景

首先,我在 Node 上运行了一个 Restify 服务,当我使用 GUI HTTP 客户端时它运行良好。我只声明前面要强调的,这是一个以浏览器为中心的问题。而如果需要服务器端的解决方案,那就是容纳浏览器……

以下是使用我的 Restify Web 服务和 GUI HTTP 客户端的 100% 功能 HTTP 请求和响应:

请求 -

POST /appointments HTTP/1.1
Content-Type: application/json
Accept: application/json
Host: localhost:8085
Connection: close
User-Agent: Paw/2.1.1 (Macintosh; OS X/10.10.1) GCDHTTPRequest
Content-Length: 142


  "eventName": "Fiesta Forever",
  "time": "Fri Dec 19 2014 15:55:00 GMT-0600 (CST)",
  "phoneNumber": "13125555555"
 

回应-

HTTP/1.1 201 Created
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Max-Age: 1000
Content-Type: application/json
Content-Length: 37
Date: Fri, 19 Dec 2014 23:01:29 GMT
Connection: close

"message":"Alright Alright Alright"

更重要的是,我的服务器创建了一个未来的 cron 作业,可以在我的服务器控制台中看到:

Created: Fri Dec 19 2014 14:55:00 GMT-0600 (CST)



问题

我的问题是我正在尝试为我的服务编写一个浏览器界面。当我尝试使用 Ajax 发出相同的 HTTP 请求时出现错误。我创建了以下发出 HTTP 请求的测试函数:

function testPost() 
    var jsonBody = "\"eventName\": \"Fiesta Forever\",\"time\": \"Fri Dec 19 2014 14:15:00 GMT-0600 (CST)\",\"phoneNumber\": \"13125555555\"";

    $.ajax(
        url: 'http://localhost:8085/appointments',
        accepts: 'application/json',
        type: 'POST',
        data: jsonBody,
        contentType: 'application/json',
        crossDomain: true,
        headers: 
         "Access-Control-Allow-Origin":true
           
    );


然后我在我的 ios 模拟器中加载包含该函数的页面,并从 Safari 开发者控制台调用该函数。我收到以下错误:

编辑:删除请求标头后,我收到: Failed to load resource: the server responded with a status of 406 (Not Acceptable)

服务器代码

这是我服务器上的代码。我从 Express 文档中获取了以下代码,因为它们是实际上似乎为每个响应添加正确标头的唯一解决方案:

//CORS
server.use(function(req, res, next) 
    res.header("Access-Control-Allow-Origin", "*");
    res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
    res.header("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
    res.header("Access-Control-Max-Age", "1000");
    next();
);

谁能帮我弄清楚如何使用携带和接收 JSON 的 $.ajax 发出跨域 HTTP 请求?

【问题讨论】:

server.use 是否高于所有其他 http 请求回调?如果不把它移到上面 405 有点奇怪。跨域错误不是,那东西很困难并且有很多怪癖。对于 405,我会在 Node 服务的 req 对象中的标头和方法上执行 console.log(),以确保您知道服务器正在尝试处理什么。 Ryan,感谢您的提示,但将 server.use 移到其他所有位置之上并没有解决问题。 Jakerella,我很想检查节点服务中传入的reqs,但我似乎找不到被命中的断点。该请求实际上并没有命中我的/appointments/ 端点,所以我不能在那里或函数处理程序中放置断点。 Sending Access-Control-Allow-Origin 标头与您的 request 是无稽之谈 - 该标头必须通过 response 发送服务器——所以从你的 AJAX 请求中删除它。 406 意味着(根据定义),服务器无法提供您通过 Accept 标头请求的类型的响应。尝试从您的 AJAX 设置中删除 accepts: 'application/json' - 这会改变什么吗? 【参考方案1】:

首先,Access-Control-Allow-Origin 是一个 response 标头,必须由服务器发送 - 将其作为 request 标头与客户端请求一起发送不仅没有意义,但似乎是服务器在这里拒绝您的请求的原因 - 因为Access-Control-Allow-Headers: Origin, X-Requested-With, Content-Type, Accept 它告诉您它将接受哪些请求标头,而Access-Control-Allow-Origin 不在其中。

之后你得到一个406 Not Acceptable,这意味着服务器看不到自己能够响应通过Accept 标头请求的内容类型的数据。所以删除 accepts: 'application/json' 确实让 jQuery 不再告诉服务器你期望一个特定的内容类型,而只是“给我你得到的任何东西”——在这种情况下,这似乎满足了服务器......

... 并让它以Content-Type: application/json 响应,这有点奇怪,因为这应该正是 jQuery 所要求的(并且您通过 GUI 的第一个请求也显示了)。我不知道 jQuery 是否从该设置中产生了其他东西(您可以尝试查看浏览器的开发人员工具网络面板是否显示请求标头有任何问题)……但是问题解决了,这才是最重要的,对吧? :-)

【讨论】:

以上是关于(浏览器作为客户端)$.ajax 上的 HTTP 405 POST 到节点服务的主要内容,如果未能解决你的问题,请参考以下文章

实现 HTTP 代理以克服跨站点 AJAX 请求限制 (?)

Javascript,ajax和内存使用情况

servlet

Servlet 简介

Ajax入门与应用

http---ajax