通过 AJAX 进行跨域资源共享 (CORS)

Posted

技术标签:

【中文标题】通过 AJAX 进行跨域资源共享 (CORS)【英文标题】:Cross Origin Resource Sharing (CORS) via AJAX 【发布时间】:2017-10-06 17:07:44 【问题描述】:

我知道有很多关于这个主题的问题,我已经尝试解决这个问题一段时间了。请纵容我在这个特定的情况下。

我的目标:

我正在尝试从以下 URL 获取 JSON 数据:

https://www.icims.com/bellworks

我正在使用以下 AJAX 请求:

$.ajax(

    url: "https://www.icims.com/bellworks", 

    success: function(res)
        console.log(res);
    
);

我的问题:

我收到以下错误:

跨域请求被阻止:同源策略不允许读取 https://www.icims.com/bellworks 的远程资源。 (原因:CORS 预检通道未成功)。

尽管直接访问 URL 会在标头中提供以下内容:

Access-Control-Allow-Origin: *

我已经下载了支持 CORS 的 Firefox 和 Chrome 扩展程序,这很有效!我能够得到数据。

我的问题:

这些 CORS 插件在做什么,我没有?

显然,这是我需要添加到 源端的客户端的东西,对吗?也就是说,我需要对我的 AJAX 请求进行更改。我确实不需要对响应服务器进行任何更改。

我需要在我的请求中添加什么来纠正这个问题?

【问题讨论】:

见这里:developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS 你试过了吗? ***.com/a/42554319/2506219 标头放在 GET 请求上,但没有 OPTIONS 预检请求。 您对该网址的响应看起来更像jsonp - 它有一个围绕 json 的方法调用。 bellway(...json...) 即,即使您确实设法发出 CORS 请求,您也无法解析 json。这将是无效的。 【参考方案1】:

“原因:CORS 预检通道未成功”

从您的错误消息中可以看出,ajax 调用会生成一个被 cors 阻止的“选项”请求。 (访问控制允许方法)

检查一下,也许有帮助:https://enable-cors.org/server_nginx.html

【讨论】:

【参考方案2】:

服务器响应还应包含此标头:“Access-Control-Allow-Methods”。它的值可以是“POST, GET, OPTIONS”以允许预检请求。见文档。 https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods

【讨论】:

【参考方案3】:

我收到以下错误:

跨域请求被阻止:同源策略不允许读取 https://www.icims.com/bellworks 的远程资源。 (原因:CORS 预检通道未成功)。

尽管直接访问 URL 会得到以下结果 在标题中:

Access-Control-Allow-Origin: *

你在哪里看到的?我在来自https://www.icims.com/bellworks 的响应中根本看不到任何Access-Control-Allow-Origin 响应标头——在浏览器开发工具中也没有,例如curl

$ curl -i -H "Origin: http://example.com" https://www.icims.com/bellworks
HTTP/1.1 200 OK
Age: 141
Cache-Control: public, max-age=1800
Content-Type: application/javascript; charset=utf-8
Date: Tue, 09 May 2017 10:17:38 GMT
Etag: "1494323930-1"
Expires: Sun, 19 Nov 1978 05:00:00 GMT
Last-Modified: Tue, 09 May 2017 09:58:50 GMT
Server: nginx
Vary: Cookie,Accept-Encoding
Via: 1.1 varnish
X-AH-Environment: prod
X-Cache: HIT
X-Cache-Hits: 2
X-Content-Type-Options: nosniff
X-Drupal-Cache: HIT
X-Request-ID: v-66496654-34a0-11e7-ba07-22000a2c8dd2
X-Varnish: 2264707046 2264675783
Content-Length: 6443
Connection: keep-alive

在这样的简单情况下,如果 1) 您不控制要从前端 JS 代码中获取数据的服务器,并且 2) 该服务器未在其响应中发送 Access-Control-Allow-Origin,您可以更改您的前端代码改为通过开放的 CORS 代理发出请求:

$.ajax(    
    url: "https://cors-anywhere.herokuapp.com/https://www.icims.com/bellworks",
    …
);

这将导致向https://cors-anywhere.herokuapp.com 发出请求,然后将其发送到https://www.icims.com/bellworks 的代理。当该代理收到响应时,它会接受它并向其添加Access-Control-Allow-Origin 响应标头,然后将其作为响应传递回您的请求前端代码。

带有Access-Control-Allow-Origin 响应标头的响应是浏览器看到的,因此浏览器引擎现在向您显示的错误消息消失了,浏览器允许您的前端 JavaScript 代码访问响应。

或者使用https://github.com/Rob--W/cors-anywhere/的代码或者类似的代码来设置你自己的代理。

这些 CORS 插件做了哪些我没有做的事情?

它们的不同之处在于,它们只是没有被浏览器阻止。插件可以做任何他们想做的事——包括绕过浏览器对前端 JavaScript 代码施加的跨域限制,浏览器执行代码的时候是在其中。

浏览器 devtools 也不受跨域限制的影响——如果您使用 devtools 检查收到 Cross-Origin Request Blocked 消息的请求,您会注意到您实际上可以在 devtools 中看到响应。但这并不意味着浏览器一定会将响应暴露给您的前端 JavaScript 代码。如果响应包含 Access-Control-Allow-Origin 标头,浏览器只会让您的前端 JavaScript 代码访问它。

显然,这是我需要添加到 源端的客户端的东西,对吗?

没有。您在客户端执行的任何操作都不会改变这样一个事实:如果您的前端 JS 代码发出跨域请求并且响应不包含 Access-Control-Allow-Origin 标头,您的浏览器将阻止您的代码访问响应。期间。

也就是说,我需要对我的 AJAX 请求进行更改。

不,因为上面给出的原因。

我确实不需要对响应服务器进行任何更改。

您确实需要更改响应服务器以发送Access-Control-Allow-Origin 标头。或者如上所述,您需要通过代理发送请求,该代理会将Access-Control-Allow-Origin 标头添加到浏览器看到的响应中。

我需要在我的请求中添加什么来纠正这个问题?

如果您无法控制发出请求的服务器,那么您唯一的选择就是更改代码,改为通过添加了Access-Control-Allow-Origin 的代理发出请求。

【讨论】:

以上是关于通过 AJAX 进行跨域资源共享 (CORS)的主要内容,如果未能解决你的问题,请参考以下文章

ajax跨域原理 cors跨域资源共享

解决ajax跨域请求的问题-cors(资源共享方案)

需要使用 jQuery Ajax 使用 Web API - 跨域资源共享 (CORS) 问题

Ajax解决跨域--设置CORS响应头实现跨域

AJAX学习笔记2:XHR实现跨域资源共享(CORS)以及和JSONP的对比

AJAX入门