CORS-在预检请求后发出的请求期望“访问控制允许凭据”为true

mat*_*ilk 3 javascript ajax jquery zend-framework cors

我将一如既往地尽我所能,让我的问题变得甜美而干净。

我必须发送CORS作为需求请求,并且正在通过$ .ajax完成,它看起来像这样:

$.ajaxSetup({
        beforeSend: function (jqXHR, options) {
            options.url = Utils.setUrlHostname(options.url);
            options.xhrFields = {
                withCredentials: true
            };
            jqXHR.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        }
    });
Run Code Online (Sandbox Code Playgroud)

在服务器端(php-zend框架),我正在处理标头,如下所示:

public function OPTIONS_ProxyAction()
    {
        $this->getResponse()->setHeader('Access-Control-Allow-Methods', 'OPTIONS, GET, POST, PUT, DELETE');
        $this->getResponse()->setHeader('Access-Control-Allow-Headers', 'Content-Type, x-requested-with');
        $this->getResponse()->setHeader('Access-Control-Allow-Credentials', 'true');
        $this->getResponse()->setBody(null);
        $this->_helper->viewRenderer->setNoRender(true);
    }
Run Code Online (Sandbox Code Playgroud)

预检请求标头看起来很好,我得到200的确定:

请求标头:

Host: domain1111.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Origin: https://domain2222.com
Access-Control-Request-Method: GET (this is seen as OPTIONS in network tab)
Access-Control-Request-Headers: x-requested-with
Connection: keep-alive
Cache-Control: max-age=0
Run Code Online (Sandbox Code Playgroud)

和响应标题:

Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: X-Requested-With, Content-Type
Access-Control-Allow-Methods: OPTIONS, GET, POST, PUT, DELETE
Access-Control-Allow-Origin: https://domain2222.com
Cache-Control: max-age=0, s-maxage=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Length: 0
Content-Type: text/html
Date: Thu, 11 Jun 2015 08:40:42 GMT
Etag: "d41d8cd98f00b204e9800998ecf8427e"
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Keep-Alive: timeout=5, max=100
Pragma: no-cache
Server: Apache
Vary: X-CDN
X-Frame-Options: SAMEORIGIN
X-Ua-Compatible: IE=edge,chrome=1
Run Code Online (Sandbox Code Playgroud)

我得到的响应是空的,这很好,并且将新请求发送到相同的地址,但是方法是GET而不是OPTIONS,它看起来像这样:

请求标头:

Host: domain1111.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:38.0) Gecko/20100101 Firefox/38.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
X-Requested-With: XMLHttpRequest
Referer: https://domain2222.com/some/request
Origin: https://domain1111.com
Cookie: s1=533C36A9095C003A; 
BGUID=some complicated guid here
Connection: keep-alive
Cache-Control: max-age=0
Run Code Online (Sandbox Code Playgroud)

和回应:

Access-Control-Allow-Origin: https://domain2222.com
Cache-Control: max-age=0, s-maxage=0, no-store, no-cache, must-revalidate, post-check=0, pre-check=0
Connection: Keep-Alive
Content-Length: 3278
Content-Type: application/json
Date: Thu, 11 Jun 2015 08:40:43 GMT
Expires: Thu, 01 Jan 1970 00:00:00 GMT
Keep-Alive: timeout=5, max=99
Pragma: no-cache
Server: Apache
Vary: X-CDN
X-Frame-Options: SAMEORIGIN
Run Code Online (Sandbox Code Playgroud)

问题是,在发送真正的请求后,我进入了Firefox:

跨域请求被阻止:同源策略禁止在https://domain1111.com/some/request读取远程资源。(原因:CORS标头“ Access-Control-Allow-Credentials”中应为“ true”)

同样在Chrome中:

XMLHttpRequest无法加载https://domain1111.com/some/request。凭据标志为“ true”,但“ Access-Control-Allow-Credentials”标头为“”。允许使用凭据必须为“ true”。

当第二个CORS请求完成时,将发生这些错误。因此,在发送第一个预检请求后,它将返回200 OK和空响应,这很好。发送第二个请求后,我收到上面列出的错误,没有返回任何数据。

此外,Firefox中的“响应”选项卡还显示以下消息:

SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 on the JSON data
Run Code Online (Sandbox Code Playgroud)

我不确定在第二个请求中是否也发送了属性'withCredential',也许服务器没有返回:

'Access-Control-Allow-Credentials', 'true'
Run Code Online (Sandbox Code Playgroud)

为什么只有OPTIONS请求会发生这种情况?

无论使用哪种请求方法,我都应该从服务器返回这些标头吗?也许ajaxSetup有问题?也许不应该在第二个CORS请求中发送“ withCredentials:true”?

更新:

通过向服务器返回的所有响应(PUT,GET,POST,DELETE,OPTIONS)添加Access-Control-Allow-Credentials:true,可以解决此问题。

Blu*_*eft 5

按照W3C的CORS文档§7.1.5步骤3中,这两个预检和实际要求必须执行“资源共享检查”。从§7.2定义检查的地方开始:

  1. 如果响应包含零个或多个Access-Control-Allow-Origin报头值,则返回失败并终止该算法。

[..]

  1. 如果omit credentials未设置该标志并且响应包括零个或多个Access-Control-Allow-Credentials报头值,则返回失败并终止此算法。

换句话说,飞行前和实际响应都必须同时包含Access-Control-Allow-Origin标头和标头(如果使用了Access-Control-Allow-Credentials标头)。