不一致的AJAX预检选项请求

时间:2016-01-06 15:30:39

标签: jquery ajax cross-domain cors preflight

我希望这个问题不是太模糊,但我觉得我错过了一些基本的东西。以下是我所处的情况。我们有一个胖客户端应用程序,可以在每个用户的本地计算机(Windows 7)上运行,并提供一个JavaScript API来与应用程序进行交互。我们有一个托管在服务器上的Web应用程序,但是向localhost发出AJAX请求以与胖客户端JS API进行交互。

在一台计算机上,我们加载了网络应用。向localhost发出的所有AJAX请求都没有OPTIONS预检请求。 JS控制台的网络选项卡显示正在进行的POST,并且响应成功(我告诉胖客户端在响应中包含哪些标头,包括所有必需的CORS标头)。

在另一台计算机上,我们从同一台服务器加载Web应用程序。但是,当向localhost发出AJAX请求时,会发出(预期的)OPTIONS请求。不幸的是,胖客户端没有使用适当的Access-Control-Allow-Origin标头进行响应,因此不允许进行后续的POST。

浏览器不重要,我们测试了最新版本的Firefox和Chrome,我们总是从机器上获得相同的行为。我们已经在4台机器上进行了测试 - 2台发送OPTIONS,2台只发送没有先前OPTIONS的POST。似乎是由浏览器决定AJAX目的地是否与原点不同以及它是否发送预检请求。我无法解释为什么我的机器没有发出任何OPTIONS请求,即使AJAX请求(对于localhost或lvh.me)与源不同的主机/域也是如此。的网页,但从另一台机器加载相同的页面确实产生了它们。

是否有某种影响这种情况的浏览器设置?还是Windows设置?为什么我们会在这上面看到不同的行为?

UPDATE1:

为了简化和澄清,我有两台机器,machineA和machineB。两台计算机都从远程服务器example.com加载Web应用程序。两台机器都在其本地机器上安装了一个完整的厚实应用程序,提供Web服务器和API。从example.com加载的Web应用程序包含用于向localhost提交AJAX请求的JavaScript代码,以便每个用户可以与他们自己的胖客户端应用程序的本地实例进行交互。从localhost!= example.com开始,请求应被视为跨域。

当machineA向localhost提交标准的jQuery AJAX请求时(其中,POST的有效负载只是" true",这将导致胖客户端回显值 - 仅用于轮询为了确定胖客户端是否可用,POST是直接进行的,没有OPTIONS请求: POST http://localhost:4000/cgi-bin/Extensions/GeoLinkConsole/evaljs.html 200 OK 0ms 有趣的是,来自该POST的响应必须包含带有example.com的Access-Control-Allow-Origin标头,以避免出现CORS错误。

当machineB从example.com加载同一页面时,将相同的标准jQuery AJAX请求提交给localhost,使用相同的" true"有效负载,浏览器提交OPTIONS请求。这是我实际期望的行为。 OPTIONS请求响应200 OK,但它不包含Access-Control-Allow-Origin标头,因此它阻止POST通过。这不是我的主要关注点,显然是胖客户端的问题。我最大的问题是为什么有些机器正在生成OPTIONS而有些机器没有生成OPTIONS。我希望这有助于解释。

更新2:

我包括两组请求标头。我不知道实际的请求标头可能会影响是否会生成OPTIONS请求。马上,我发现发送OPTIONS的那个包括一个Acces-Control-Request-Headers和Access-Control-Request_Method,而另一个没有......

从发送没有OPTIONS的POST的机器请求标头:

Accept:    text/plain, */*; q=0.01
Accept-Encoding:    gzip, deflate
Accept-Language:    en-US,en;q=0.5
Content-Length:    354
Content-Type:   text/plain; charset=UTF-8
Host:    localhost:4000
Origin:    http://example.com:7802
Referer:    http://example.com:7802/
User-Agent:    Mozilla/5.0 (Windows NT 6.1; WOW64; rv:43.0) Gecko/20100101 Firefox/43.0

从发送OPTIONS的计算机请求标头:

Accept:    */*
Accept-Encoding:    gzip, deflate, sdch
Accept-Language:    en-US,en;q=0.8
Access-Control-Request-Headers:    accept, content-type, x-csrftoken
Access-Control-Request-Method:    POST
Connection:    keep-alive
Host:    localhost:4000
Origin:    http://example.com:7802
Referer:    http://example.com:7802/
User-Agent:    Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36

此外,该机器有一个" general"标题块 - 我假设我刚刚发布的请求标题是针对原始POST请求的,这些与预检OPTIONS请求有关:

Request URL:    http://localhost:4000/cgi-bin/Extensions/GeoLinkConsole/evaljs.html
Request Method:   OPTIONS
Status Code:    200 OK
Remote Address:    127.0.0.1:4000

1 个答案:

答案 0 :(得分:4)

(您可能有兴趣阅读How does Access-Control-Allow-Origin header work? HTML5 writeup on CORS上我的答案的“非简单”药水,以便了解OPTIONS预检请求发生的原因。)

如您所见,OPTIONS请求包含Access-Control-Request-Headers,其中包含标题名称x-csrftoken。这意味着JavaScript正在尝试发送名为x-csrftoken的标头。由于这不是简单的CORS标头(即AcceptAccept-LanguageContent-Language,有时是Content-Type),因此必须首先允许预检OPTIONS请求。< / p>

除了正常的Access-Control-Allow-Origin标头之外,服务器还应使用包含Access-Control-Allow-Headers标头名称的x-csrftoken标头响应OPTIONS预检。完成后,浏览器将允许实际的POST请求进入服务器。

或者,完全删除非简单的x-csrftoken标题,并且不需要预检。