2

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

在一台机器上,我们加载 Web 应用程序。向 localhost 发出的所有 AJAX 请求都是在没有 OPTIONS 预检请求的情况下发出的。JS 控制台的 net 选项卡显示正在发出的 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 设置?为什么我们会在这方面看到不同的行为?

更新1:

为了简化和澄清,我有两台机器,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 的响应必须包括 Access-Control-带有 example.com 的 Allow-Origin 标头,以避免 CORS 错误。

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

更新 2:

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

来自发送 POST 且没有 OPTIONS 的机器的请求标头:

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

此外,机器有一个“通用”标头块——我假设我刚刚发布的请求标头用于原始 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
4

1 回答 1

5

(您可能有兴趣阅读我关于Access-Control-Allow-Origin 标头如何工作的答案中的“非简单”药水? CORS上的HTML5 文章,以了解为什么会发生 OPTIONS 预检请求。)

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

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

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

于 2016-01-06T17:12:08.450 回答