CORS 已启用,但仍出现 CORS 错误

Posted

技术标签:

【中文标题】CORS 已启用,但仍出现 CORS 错误【英文标题】:CORS enabled but still getting CORS error 【发布时间】:2017-04-29 16:13:52 【问题描述】:

我正在尝试从 API 获取 JSON 对象,API 的开发人员说他们刚刚启用了 CORS,但我仍然收到以下错误。

XMLHttpRequest 无法加载 http://example.com/data/action/getGame/9788578457657。请求的资源上不存在“Access-Control-Allow-Origin”标头。 Origin 'http://dev.our-domain.local' 因此不允许访问。

我正在使用 AngularJS 在服务中获取 JSON

app.service("gameService", function ($http, $q)

    function getGame(GameId) 
      var deferred = $q.defer()
      var url = 'http://example.com/data/action/getGame/' + gameId;
      // var url = 'https://jsonplaceholder.typicode.com/albums/' + gameId;  // THIS WORKS
      $http(
        method: 'GET',
        cache: true,
        url: url,
        headers:   
           'Content-Type': 'application/json;charset=UTF-8'  
        
      ).
      then(function(response) 
        //your code when success
        deferred.resolve(response);
        console.log('gameService HTTP CORS SUCCESS!');
      , function(response) 
        //your code when fails
        console.log('gameService HTTP CORS ERROR!');
        // deferred.resolve('');        
        deferred.reject(response);
      );
      return deferred.promise;
    
    this.getGame = getGame;
)

当我使用启用了 CORS 的 jsonplaceholder 对其进行测试时,我的 AngularJS 服务可以正常工作。

我错过了什么吗?

API 开发人员说两个 CORS 标头已添加到 data.service 响应中,但我没有看到它们。这是我在 curl 向下 JSON 对象时看到的标题。

$ curl -X HEAD -i  http://example.com/data/action/getGame/9788578457657
HTTP/1.1 200 OK
Date: Wed, 14 Dec 2016 10:39:17 GMT
Server: WildFly/8
Expires: Wed, 14 Dec 2016 10:39:17 GMT
X-Powered-By: Undertow/1
X-dmg-elapsed-time: 20ms
X-dmg-host-address: 1??.??.???.??
Vary: Accept-Encoding,Origin
X-dmg-generated-time: Wed, 14 Dec 2016 10:39:17 GMT
Content-Type: application/json;charset=UTF-8
Content-Language: en-
X-dmg-node-name: defg_node_1
X-Varnish-Bereq-Backend: real_backend_foo_bar_uk
X-Varnish-Bereq-Retries: 0
Last-Modified: Wed, 14 Dec 2016 10:39:17 GMT
Cache-Control: public, max-age=300
X-Varnish: 6876870
Age: 0
Via: 1.1 varnish-v4
X-Varnish-Cache: MISS
X-Varnish-Trimen: www.trimen.com
X-Varnish-Served-By-Host: snarf.foo.uk
X-Varnish-Served-By-IP: 100.100.10.80
X-Varnish-Pool: http_pages
X-Varnish-Req-Backend-Hint: dead
X-Varnish-Req-Restarts: 0
X-Varnish-Hash: /data/action/getGame/9788578457657
X-Varnish-Backend-Ourself: varnish_server_snarf_foo_uk
X-DMG-Version: 6.20.51.2358
Accept-Ranges:  none
Connection: keep-alive

这是启用 CORS 后我应该看到的还是有更多?

在启用 Cors 的情况下,我是否需要向我的 AngularJS 服务添加更多内容,以添加更多内容:

headers:   
   'Content-Type': 'application/json;charset=UTF-8'  

更新

传递来源:在我的 curl 请求的标头中,如 @t.niese 建议的那样

$ curl -H "Origin: http://our-production-domain.com/" --verbose \
>   http://example.com/data/action/getGame/9788578457657
*   Trying 1?.???.??.???...
* Connected to http://example.com/ (1?.???.??.???) port 80 (#0)
> GET /data/action/getGame/9788578457657 HTTP/1.1
> Host: http://example.com/
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://our-production-domain.com/
> 
< HTTP/1.1 200 OK
< Date: Wed, 14 Dec 2016 11:05:24 GMT
< Server: WildFly/8
< Expires: Wed, 14 Dec 2016 11:05:24 GMT
< X-Powered-By: Undertow/1
< X-dmg-elapsed-time: 27ms
< X-dmg-host-address: 1??.??.???.??
< Vary: Accept-Encoding,Origin
< X-dmg-generated-time: Wed, 14 Dec 2016 11:05:24 GMT
< Content-Type: application/json;charset=UTF-8
< Content-Language: en-
< X-dmg-node-name: defg_node_1
< X-Varnish-Bereq-Backend: real_backend_foo_bar_uk
< X-Varnish-Bereq-Retries: 0
< Last-Modified: Wed, 14 Dec 2016 11:05:24 GMT
< Cache-Control: public, max-age=300
< X-Varnish: 6876870
< Age: 0
< Via: 1.1 varnish-v4
< X-Varnish-Cache: MISS
< X-Varnish-Trimen: www.trimen.com
< X-Varnish-Served-By-Host: snarf.foo.uk
< X-Varnish-Served-By-IP: 100.100.10.80
< X-Varnish-Pool: http_pages
< X-Varnish-Req-Backend-Hint: dead
< X-Varnish-Req-Restarts: 0
< X-Varnish-Hash: /data/action/getGame/9788578457657
< X-Varnish-Backend-Ourself: varnish_server_snarf_foo_uk
< X-DMG-Version: 6.20.51.2358
< Accept-Ranges:  none
< Transfer-Encoding: chunked
< Connection: keep-alive
< 

  "errorMessage" : null,
  "expiry" : "2016-12-14T11:05:24.379+0000",
  "data" : 
    // json object data here
  
* Connection #0 to host http://example.com/ left intact

和..

$ curl -H "Origin: http://qa.our-qa-domain.com/" --verbose \
>   http://example.com/data/action/getGame/9788578457657
*   Trying 1?.???.??.???...
* Connected to http://example.com/ (1?.???.??.???) port 80 (#0)
> GET /data/action/getGame/9788578457657 HTTP/1.1
> Host: http://example.com/
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://qa.our-qa-domain.com/
> 
< HTTP/1.1 200 OK
< Date: Wed, 14 Dec 2016 11:06:11 GMT
< Server: WildFly/8
< Expires: Wed, 14 Dec 2016 11:06:11 GMT
< X-Powered-By: Undertow/1
< X-dmg-elapsed-time: 18ms
< X-dmg-host-address: 1??.??.???.??
< Vary: Accept-Encoding,Origin
< X-dmg-generated-time: Wed, 14 Dec 2016 11:06:11 GMT
< Content-Type: application/json;charset=UTF-8
< Content-Language: en-
< X-dmg-node-name: defg_node_1
< X-Varnish-Bereq-Backend: real_backend_foo_bar_uk
< X-Varnish-Bereq-Retries: 0
< Last-Modified: Wed, 14 Dec 2016 11:06:11 GMT
< Cache-Control: public, max-age=300
< X-Varnish: 1343699
< Age: 0
< Via: 1.1 varnish-v4
< X-Varnish-Cache: MISS
< X-Varnish-Trimen: www.trimen.com
< X-Varnish-Served-By-Host: snarf.foo.uk
< X-Varnish-Served-By-IP: 100.100.10.80
< X-Varnish-Pool: http_pages
< X-Varnish-Req-Backend-Hint: dead
< X-Varnish-Req-Restarts: 0
< X-Varnish-Hash: /data/action/getGame/9788578457657
< X-Varnish-Backend-Ourself: varnish_server_snarf_foo_uk
< X-DMG-Version: 6.20.51.2358
< Accept-Ranges:  none
< Content-Length: 2988
< Connection: keep-alive
< 

  "errorMessage" : null,
  "expiry" : "2016-12-14T11:06:11.927+0000",
  "data" : 
     // json data object here
  
* Connection #0 to host http://example.com/ left intact

和..

$ curl -H "Origin: http://dev.my-dev.local/" --verbose \
>   http://example.com/data/action/getGame/9788578457657
*   Trying 1?.???.??.???...
* Connected to http://example.com/ (1?.???.??.???) port 80 (#0)
> GET /data/action/getGame/9788578457657 HTTP/1.1
> Host: http://example.com/
> User-Agent: curl/7.43.0
> Accept: */*
> Origin: http://dev.my-dev.local/
> 
< HTTP/1.1 200 OK
< Date: Wed, 14 Dec 2016 11:07:10 GMT
< Server: WildFly/8
< Expires: Wed, 14 Dec 2016 11:07:10 GMT
< X-Powered-By: Undertow/1
< X-dmg-elapsed-time: 28ms
< X-dmg-host-address: 1??.??.???.??
< Vary: Accept-Encoding,Origin
< X-dmg-generated-time: Wed, 14 Dec 2016 11:07:10 GMT
< Content-Type: application/json;charset=UTF-8
< Content-Language: en-
< X-dmg-node-name: defg_node_1
< X-Varnish-Bereq-Backend: real_backend_foo_bar_uk
< X-Varnish-Bereq-Retries: 0
< Last-Modified: Wed, 14 Dec 2016 11:07:10 GMT
< Cache-Control: public, max-age=300
< X-Varnish: 6619151
< Age: 0
< Via: 1.1 varnish-v4
< X-Varnish-Cache: MISS
< X-Varnish-Trimen: www.trimen.com
< X-Varnish-Served-By-Host: snarf.foo.uk
< X-Varnish-Served-By-IP: 100.100.10.80
< X-Varnish-Pool: http_pages
< X-Varnish-Req-Backend-Hint: dead
< X-Varnish-Req-Restarts: 0
< X-Varnish-Hash: /data/action/getGame/9788578457657
< X-Varnish-Backend-Ourself: varnish_server_snarf_foo_uk
< X-DMG-Version: 6.20.51.2358
< Accept-Ranges:  none
< Content-Length: 2988
< Connection: keep-alive
< 

  "errorMessage" : null,
  "expiry" : "2016-12-14T11:07:10.764+0000",
  "data" : 
        // JSON object data here
  
* Connection #0 to host http://example.com/ left intact

第二次更新

我在 Chrome 中禁用了同源策略,这些是来自 Chrome 网络面板的 JSON 请求的标头。

GET data/action/getGame/9788578457657 HTTP/1.1
Host: example.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: application/json, text/plain, */*
Origin: http://dev.my-dev.local/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (Khtml, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Referer: http://dev.my-dev.local//game/id-9788578457657
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

HTTP/1.1 200 OK
Date: Wed, 14 Dec 2016 15:38:38 GMT
Server: WildFly/8
Expires: Wed, 14 Dec 2016 15:38:38 GMT
X-Powered-By: Undertow/1
X-dmg-elapsed-time: 25ms
X-dmg-host-address: 172.16.0.70
Vary: Accept-Encoding,Origin
X-dmg-generated-time: Wed, 14 Dec 2016 15:38:38 GMT
Content-Type: application/json;charset=UTF-8
Content-Language: en-
X-dmg-node-name: defg_node_1
Content-Encoding: gzip
Content-Length: 1109
X-Varnish-Bereq-Backend: real_backend_foo_bar_uk
X-Varnish-Bereq-Retries: 0
Last-Modified: Wed, 14 Dec 2016 15:38:38 GMT
Cache-Control: public, max-age=300
X-Varnish: 6619151
Age: 0
Via: 1.1 varnish-v4
X-Varnish-Cache: MISS
X-Varnish-Trimen: www.trimen.com
X-Varnish-Served-By-Host: snarf.foo.uk
X-Varnish-Served-By-IP: 100.100.10.80
X-Varnish-Pool: http_pages
X-Varnish-Req-Backend-Hint: dead
X-Varnish-Req-Restarts: 0
X-Varnish-Hash: /data/action/getGame/9788578457657
X-Varnish-Backend-Ourself: arnish_server_snarf_foo_uk
X-DMG-Version: 6.20.51.2358
Accept-Ranges: none
Connection: keep-alive

第三次更新

所以在将http方法更改为OPTIONS之后 $http( 方法:'选项', ...

我在 chrome 控制台中遇到了这个错误

XMLHttpRequest 无法加载 http://example.com/data/action/getGame/9788578457657。对预检请求的响应未通过访问控制检查:请求的资源上不存在“Access-Control-Allow-Origin”标头。因此,Origin 'http://dev.my-dev.local'' 不允许访问。响应的 HTTP 状态代码为 405。

这些是标题:

OPTIONS /data/action/getGame/9788578457657 HTTP/1.1
Host: example.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Access-Control-Request-Method: OPTIONS
Origin: http://dev.my-dev.local/
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.98 Safari/537.36
Access-Control-Request-Headers:
Accept: */*
Referer: http://dev.my-dev.local//game/id-9788578457657
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8

HTTP/1.1 405 Method Not Allowed
Date: Wed, 14 Dec 2016 16:52:03 GMT
Server: Varnish
X-Varnish: 6619151
X-Varnish-Trimen: www.trimen.com
X-Varnish-Served-By-Host: snarf.foo.uk
X-Varnish-Served-By-IP: 100.100.10.80
X-Varnish-Pool: 
X-Varnish-Req-Backend-Hint: dead
X-Varnish-Req-Restarts: 0
X-DMG-Version: 6.20.51.2358
Content-Type: text/html; charset=utf-8
Retry-After: 5
Content-Length: 49669
Connection: keep-alive

【问题讨论】:

首先,您是否已经按照此处How can you debug a CORS request with cURL? 描述的方式尝试过(在标题中传递Origin:)?因为标头 Vary: Accept-Encoding,Origin 告诉您,如果您将 Origin 与您的请求一起传递,则会得到不同的响应,并表明可能启用了 CORS。 @t.niese ,感谢您的提示。我更新了我的问题,但我看不出这个 curl 响应有什么真正的不同? 【参考方案1】:

您需要收到以下标头:

Access-Control-Allow-Origin: *(或您想要限制的任何主机) Access-Control-Allow-Methods: *(或您想限制的任何方法) Access-Control-Allow-Headers: Content-Type

注意最后一个也很重要,因为您正在设置Content-Type: application/json;charset=UTF-8。如果您有任何其他自定义标题,您也需要添加它们。

这些都是在服务器上完成的,你的应用不需要做任何其他事情。

或者(如果可能)您可以选择完全不使用 application/json,并将您的 Content-Type 设置为 application/x-www-form-urlencodedmultipart/form-datatext/plain,并且不会完成预检 (OPTIONS) 请求并且在服务器上是否启用CORS 无关紧要。

【讨论】:

谢谢,您是说 API 服务器上不存在正确的 CORS 标头并且仍需要添加它们?如果这些标头存在,我的 AngularJS 应用程序上的内容应该足以获取 JSON 对象? 我从来没有使用过 cURL 来测试这个,所以我不确定。我没有看到那里的标题,但同时我没有看到任何确认您的请求是预检请求,即方法OPTIONS,因此您的测试请求同样可能是错误的。在发出我想要工作的实际请求时,我通常只检查浏览器内的 chrome 开发工具。您将在那里看到预检请求,如果成功,则会在其后看到另一个单独的请求 如果预检,我如何检查我的请求?我在 Chrome 中禁用了相同的来源策略,并从 Chrome 的网络面板获取了我的 JSON 请求的标头,我用详细信息更新了我的问题。这有帮助吗? Method: OPTIONS发送请求,现在说了3遍:p方法是请求方法,如POST,PUT,GET 最后一个应该是Access-Control-Allow-Headers,那么解决方案就行了【参考方案2】:

ed 的回答启发了我的解决方案

您需要在预检请求期间发送以下标头(端点的 OPTIONS 方法)

Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET,HEAD,PUT,PATCH,POST,DELETE
Access-Control-Allow-Headers: Content-Type, Access-Control-Allow-Origin, xxx

其中 xxx 是您在执行 POST/PUT/DELETE/etc 请求时发送的任何附加标头

请注意,当此解决方案有效时,我强烈建议更改 * 以将其限制为您已知的来源

【讨论】:

以上是关于CORS 已启用,但仍出现 CORS 错误的主要内容,如果未能解决你的问题,请参考以下文章

为啥启用 CORS 后仍然出现 CORS 错误

在带有 Angular 的 Spring Boot 中启用了 Cors,但仍然出现 cors 错误

在启动中启用 CORS 失败并出现预检错误

在 php 文件上启用了 Cors,但仍然出现错误

更新文档时出现 XMLHttpRequest 错误,但应启用 CORS

Owin Self Host WebApi2 上的 CORS 错误