与往常一样,我会尽可能地将问题变得干净利落。
我必须发送CORS作为需求请求,我是通过$ .ajax进行的,它看起来像这样:
$.ajaxSetup({
beforeSend: function (jqXHR, options) {
options.url = Utils.setUrlHostname(options.url);
options.xhrFields = {
withCredentials: true
};
jqXHR.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
}
});
在服务器端(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);
}
预检请求标题看起来很好,我得到200 OK:
请求标题:
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
响应标题:
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
我得到空响应,这很好,并且新请求被发送到同一个地址,但该方法是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
并回应:
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
问题是在发送真实请求后,我进入Firefox:
阻止跨源请求:同源策略禁止读取 https://domain1111.com/some/request处的远程资源。 (原因: 在CORS标题'Access-Control-Allow-Credentials'中预期'true')
同样在Chrome中:
XMLHttpRequest无法加载https://domain1111.com/some/request。 凭据标志为“true”,但“Access-Control-Allow-Credentials” 标题是''。允许凭证必须是“真实的”。
第二个CORS请求完成时会发生这些错误。 因此,在发送第一个预检请求后,它返回200 OK和空响应,这很好;发送第二个请求后,我收到上面列出的错误,没有返回数据。
此外,Firefox中的“响应”选项卡正在向我发送以下消息:
SyntaxError: JSON.parse: unexpected end of data at line 1 column 1 on the JSON data
我不确定在第二次请求期间是否也发送了'withCredential'属性,也许服务器没有返回:
'Access-Control-Allow-Credentials', 'true'
为什么只有OPTIONS请求才会发生?
无论请求方法是什么,我都应该从服务器返回这些标头吗?或者也许ajaxSetup有问题?也许它不应该在第二个CORS请求中发送'withCredentials:true'?
更新
通过添加Access-Control-Allow-Credentials解决了该问题: 对于服务器返回的所有响应(PUT,GET,POST,DELETE,OPTIONS)
答案 0 :(得分:4)
根据W3C CORS docs,§7.1.5第3步,预检和实际请求都必须执行资源共享检查"。从定义该检查的§7.2开始:
- 如果响应包含零个或多个
醇>Access-Control-Allow-Origin
标头值,则返回失败并终止此算法。[..]
- 如果未设置
醇>omit credentials
标志且响应包含零个或多个Access-Control-Allow-Credentials
标头值,则返回失败并终止此算法。
换句话说,预检和实际响应都必须包含Access-Control-Allow-Origin
标头,如果使用,则必须包含Access-Control-Allow-Credentials
标头。
答案 1 :(得分:0)
我认为你需要为所有请求(飞行前和正常)返回CORS策略。我也认为这种行为有所改变。我记得只是在飞行前请求上实施了CORS政策。
我无法确定,但我认为浏览器的行为也不同。例如,Chrome现在始终会发送Origin
标题,而不仅仅是在发布前请求。
我的当前实现(仅)查找Origin标头,如果需要CORS策略(Origin!= domain),则返回它。
我还没有找到任何关于如何正确实施CORS的明确指南或标准文档。
答案 2 :(得分:0)
仅为您的OPTIONS请求返回标头。 OPTIONS_ProxyAction()
当发送参数Access-Control-Allow-Credentials: true
时,需要为所有CORS请求(GET,POST ...)维护此标头withCredentials: true
。
有关参数
的更多信息options.xhrFields = {
withCredentials: true
};
和标题Access-Control-Allow-Credentials
看看这篇文章:
http://www.ozkary.com/2015/12/api-oauth-token-access-control-allow-credentials.html
希望它有所帮助。