由于标准标头,CORS 预检请求失败

新手上路,请多包涵

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

 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'

如果出现以下情况,则服务器对此请求的响应:

 < 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 请求成功并出现以下响应:

 < 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 规范标准标头,因此它不应该阻止请求成功,对吗?为什么这个标头会导致这种行为?

以及如何调整服务器发送的访问控制标头以使使用 Chrome 发出的请求有效?

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

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

任何想法?

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

原文由 joanlofe 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 656
2 个回答

经过一番折腾,终于找到了问题所在。我在 Spring 中配置了一个请求映射来处理 OPTIONS 流量,如下所示:

 @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 注释添加到适当的请求映射解决了这个问题。

原文由 joanlofe 发布,翻译遵循 CC BY-SA 3.0 许可协议

我也遇到了同样的问题,并找到了在 spring boot 中启用全局 cors 问题的解决方案

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedMethods("GET", "POST", "PUT", "DELETE").allowedOrigins("*")
                .allowedHeaders("*");
    }
}

在此之后,我们还需要在 spring 安全级别启用 CORS,因此为此在您的 SecurityConfiguration 类中添加 cors() ,扩展 WebSecurityConfigurerAdapter

  @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        httpSecurity
                .cors()
                .and()
                .csrf().disable()
                .authorizeRequests()..

    }

原文由 Om Prakash Sharma 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题