由于标准标头,CORS预检请求失败 [英] CORS preflight request fails due to a standard header

查看:469
本文介绍了由于标准标头,CORS预检请求失败的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在调试我遇到的CORS问题时,我发现以下行为. Chrome发出以下OPTIONS预检请求(由Chrome本身在CURL中重写):

While debugging a CORS issue I am experiencing I've found the following behaviour. Chrome makes the following OPTIONS preflight request (rewritten in CURL by Chrome itself):

curl -v 'https://www.example.com/api/v1/users' -X OPTIONS -H 'Access-Control-Request-Method: POST' -H 'Origin: http://example.com' -H 'Accept-Encoding: gzip,deflate,sdch' -H 'Accept-Language: es-ES,es;q=0.8,en;q=0.6' -H 'User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.125 Safari/537.36' -H 'Accept: */*' -H 'Referer: http://example.com/users/new' -H 'Connection: keep-alive' -H 'Access-Control-Request-Headers: accept, x-api-key, content-type'

如果满足以下条件,则服务器对此请求的响应:

The response from the server to this request if the following:

< HTTP/1.1 403 Forbidden
< Date: Thu, 21 Jul 2016 14:16:56 GMT
* Server Apache/2.4.7 (Ubuntu) is not blacklisted
< Server: Apache/2.4.7 (Ubuntu)
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains
< X-Frame-Options: SAMEORIGIN
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
< Content-Length: 20
< Keep-Alive: timeout=5, max=100
< Connection: Keep-Alive

是响应无效的CORS请求"的正文.如果我重复删除标题"Access-Control-Request-Method"(仅该标题)的请求,则OPTIONS请求成功,并显示以下响应:

being the body of the response 'Invalid CORS request'. If I repeat the request removing the header 'Access-Control-Request-Method' (and only that header) the OPTIONS requests succeeds with the following reponse:

< HTTP/1.1 200 OK
< Date: Thu, 21 Jul 2016 14:21:27 GMT
* Server Apache/2.4.7 (Ubuntu) is not blacklisted
< Server: Apache/2.4.7 (Ubuntu)
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< Strict-Transport-Security: max-age=31536000 ; includeSubDomains
< X-Frame-Options: SAMEORIGIN 
< Access-Control-Allow-Headers: origin, content-type, accept, x-requested-with, x-api-key
< Access-Control-Max-Age: 60
< Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
< Access-Control-Allow-Origin: *
< Allow: GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
< Content-Length: 0
< Keep-Alive: timeout=5, max=100
< Connection: Keep-Alive

但是,有问题的标头是 CORS规范标准标头,因此它不应阻止请求成功,对吧?为什么此标头会导致这种行为?

However, the offending header is a CORS spec standard header so it should not prevent the request from succeeding, right? Why is this header causing such behaviour?

在使用Chrome进行发送时,如何调整服务器发送的访问控制标头以使请求正常工作?

And how can I tweak the access control headers sent by my server to make the request work when made with Chrome?

顺便说一句,我使用的是Chrome 36.0,服务器使用的是Spring Boot,而CORS标头由Spring管理.

By the way, I am using Chrome 36.0, and the server is using Spring Boot, with the CORS headers being managed by Spring.

由Firefox(v47.0)发出请求时,行为不同,但结果类似. Firefox甚至不发送预检请求,而是直接发送POST请求,该请求收到403 Forbidden作为响应.但是,如果我使用复制为cURL"选项复制请求,并从终端窗口重复该请求,它将成功并在响应中发送正确的CORS标头.

When the request is made by Firefox (v47.0) the behaviour is different but with an analogue result. Firefox does not even send the preflight request, it directly sends the POST request, which receives as response a 403 Forbidden. However, if I copy the request with the 'Copy as cURL' option, and repeat it from a terminal window, It succeeds and sends the correct CORS headers in the response.

有什么主意吗?

更新:Firefox确实发送了预检OPTIONS请求(如Live HTTP标头插件所示),但是Firebug屏蔽了它,因此在两个浏览器中的行为都完全相同.在两种浏览器中,"Access-control-request-method"标头都是导致请求失败的区别.

Update: Firefox does send the preflight OPTIONS request (as shown by the Live HTTP headers plugin), but Firebug masks it, so the behaviour in both browsers it exactly the same. In both browsers is the 'Access-control-request-method' header the difference that makes the request fail.

推荐答案

经过很多努力,我终于找到了问题所在.我在Spring中配置了一个请求映射来处理OPTIONS流量,如下所示:

After a lot of struggling, I finally found the problem. I configured a request mapping in Spring to handle OPTIONS traffic, like this:

@RequestMapping(value= "/api/**", method=RequestMethod.OPTIONS)
public void corsHeaders(HttpServletResponse response) {
    response.addHeader("Access-Control-Allow-Origin", "*");
    response.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
    response.addHeader("Access-Control-Allow-Headers", "origin, content-type, accept, x-requested-with");
    response.addHeader("Access-Control-Max-Age", "3600");
}

我不知道默认情况下Spring是否使用默认的CORS处理器,它似乎正在干扰我的请求映射.删除我的请求映射并添加 @CrossOrigin 注释解决了该问题.

I did not know that by default Spring uses a default CORS processor, and it seems it was interfering with my request mapping. Deleting my request mapping and adding the @CrossOrigin annotation to the appropriate request mappings solved the problem.

这篇关于由于标准标头,CORS预检请求失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆