Chrome v37/38 CORS(再次)失败,401为OPTIONS飞行前请求

Cor*_*son 26 google-chrome cors

从Chrome版本37开始,即使所有CORS标头都设置正确,如果服务器启用了身份验证,预先发布的跨域请求也会失败(再次).这是localhost(我的开发PC).

你们中的一些人可能知道Chrome/CORS/auth错误的历史,特别是涉及HTTPS时.我的问题并没有涉及HTTPS:我有一个AngularJS应用从供应localhost:8383交谈一个Java(码头)的服务器上localhost:8081有HTTP基本身份验证激活.GET工作正常,但POST失败了401:

XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
Invalid HTTP status code 401
Run Code Online (Sandbox Code Playgroud)

我之前编写了一个自定义(Java)CORS过滤器,它设置了正确的CORS头,直到第36版.它在v37和最新的v38(38.0.2125.101 m)中失败.它仍然可以按预期使用Internet Explorer 11(11.0.9600)和Opera 12.17(build 1863).

GET请求成功,但POST失败.由于内容类型:"application/json",Chrome看起来像是在推出我的所有POST,并且它是预先发布的OPTIONS请求失败.

在Angular应用程序中,我明确设置了以下请求标头.AFAIK此设置withCredentials应确保即使对于OPTIONS请求也会发送凭据:

//Enable cross domain calls
$httpProvider.defaults.useXDomain = true;

//Send all requests, even OPTIONS, with credentials
$httpProvider.defaults.withCredentials = true;
Run Code Online (Sandbox Code Playgroud)

以下是请求/响应.您可以看到Access-Control-Allow-Methods标题中启用了OPTIONS方法.您还可以看到Javascript应用程序的来源已明确启用:Access-Control-Allow-Origin: http://localhost:8383.

Remote Address:[::1]:8081
Request URL:http://localhost:8081/cellnostics/rest/medicaltest
Request Method:OPTIONS
Status Code:401 Full authentication is required to access this resource

Request headers:

Accept:*/*
Accept-Encoding:gzip,deflate,sdch
Accept-Language:en-US,en;q=0.8,af;q=0.6
Access-Control-Request-Headers:accept, content-type
Access-Control-Request-Method:POST
Connection:keep-alive
Host:localhost:8081
Origin:http://localhost:8383
Referer:http://localhost:8383/celln-web/index.html
User-Agent:Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36

Response headers:

Access-Control-Allow-Credentials:true
Access-Control-Allow-Headers:Cache-Control, Pragma, Origin, Authorization, Content-Type, X-Requested-With, Accept
Access-Control-Allow-Methods:POST, GET, OPTIONS, PUT, DELETE
Access-Control-Allow-Origin:http://localhost:8383
Access-Control-Max-Age:3600
Content-Length:0
Server:Jetty(8.1.8.v20121106)
WWW-Authenticate:Basic realm="Cellnostics"
Run Code Online (Sandbox Code Playgroud)

有谁知道我还应该做些什么?我确保在测试,重新启动之前清除Chrome缓存,并确保在重新启动之前没有后台Chrome进程保持运行,因此我非常确定没有遗留的身份验证缓存问题.

我不得不切换到IE 11来测试我的Web开发.事实上,相同的客户端和服务器设置仍适用于IE和Opera,以及存在Chrome/CORS错误的历史,这让我怀疑Chrome.

编辑:以下是Chrome net-internals事件列表的摘录:

t=108514 [st=0]   +URL_REQUEST_START_JOB  [dt=4]
    --> load_flags = 336011264 (BYPASS_DATA_REDUCTION_PROXY | DO_NOT_SAVE_COOKIES | DO_NOT_SEND_AUTH_DATA | DO_NOT_SEND_COOKIES | MAYBE_USER_GESTURE | VERIFY_EV_CERT)
    --> method = "OPTIONS"
    --> priority = "LOW"
    --> url = "http://localhost:8081/cellnostics/rest/patient"
...
t=108516 [st=2] HTTP_TRANSACTION_SEND_REQUEST_HEADERS
--> OPTIONS /cellnostics/rest/patient HTTP/1.1
   Host: localhost:8081
   Connection: keep-alive
   Access-Control-Request-Method: POST
   Origin: http://localhost:8383
   User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.101 Safari/537.36
   Access-Control-Request-Headers: accept, content-type
   Accept: */*
   Referer: http://localhost:8383/celln-web/index.html
   Accept-Encoding: gzip,deflate,sdch
   Accept-Language: en-US,en;q=0.8,af;q=0.6
Run Code Online (Sandbox Code Playgroud)

因此,即使我明确设置,看起来Authorization标头也不会与OPTIONS pre-flight一起发送withCredentials = true.

但是,为什么IE和Opera仍然可以工作?Chrome在这方面是否更符合标准?为什么它会起作用然后从v37开始失败?

编辑:Chrome开发工具不会Content-Type在上面的转储中显示请求,但这里是来自网络日志.第一张图片显示禁用服务器身份验证时的POST,内容类型正确发送为'application/json'.第二张图片是启用身份验证时,显示OPTIONS请求失败(似乎OPTIONS始终以内容类型'text/plain'?)发送.

在服务器上没有auth的CORS POST 在服务器上启用auth的CORS POST

Ale*_* MM 7

@Cornel Masson,你解决了这个问题吗?我不明白为什么你的服务器要求你验证OPTIONS请求,但我面对SAP NetWeaver服务器的同样问题.我已经阅读了整个CORS规范(我推荐),所以我可以向你澄清一些疑问.

关于你的句子

在Angular应用程序中,我明确设置了以下请求标头.AFAIK withCredentials的此设置应确保即使对于OPTIONS请求也会发送凭据:

  • 根据CORS规范,当用户代理(因此,浏览器)预检请求(使用OPTIONS HTTP方法请求)时,它必须排除用户凭证(cookie,HTTP身份验证......),因此无法通过身份验证请求任何OPTIONS请求.浏览器将请求经过身份验证的实际请求(具有请求的HTTP方法的请求,如GET,POST ...),但不会请求预检请求.
  • 因此浏览器不得在OPTIONS请求中发送凭据.他们会在实际请求中做.如果你写withCredentials = true,浏览器应该按照我的说法去做.

根据你的判决:

由于内容类型:"application/json",Chrome看起来像是在推出我的所有POST!

  • 该规范还说,当标题不是"简单标题"时,浏览器将进行预检请求,这里你的意思是:

    如果头字段名称是Accept,Accept-Language或Content-Language的ASCII不区分大小写的匹配,或者如果它是Content-Type和头字段的ASCII不区分大小写的匹配,则称头是简单头值媒体类型(不包括参数)是对application/x-www-form-urlencoded,multipart/form-datatext/plain的ASCII不区分大小写的匹配.

  • application/json不包括在内,因此浏览器必须像预测那样预检请求.
如果有人找到解决方案,将不胜感激.

编辑:我刚发现一个有同样问题的人反映了真正的问题,如果你使用与他相同的服务器,你将很幸运,https://evolpin.wordpress.com/2012/10/12/the-cors/


小智 2

同样在这里。我使用 Windows NTLM 身份验证。直到 Chrome 版本 37 为止,它都工作正常。在版本 37、38 上,由于 PUT 和 POST 上的飞行前选项中缺少请求授权标头,因此失败并显示 401(未经授权)。

服务器端是Microsoft Web Api 2.1。我尝试了各种 CORS,包括 Microsoft 的最新 NuGet 包,但均无济于事。

我必须通过发送 GET 请求而不是 POST 来解决 Chrome 上的问题,并在多个请求中破坏相当大的数据,因为 URL 自然有大小限制。

以下是请求/响应标头:


Request URL: http://localhost:8082/api/ConfigurationManagerFeed/
Method: OPTIONS
Status: 401 Unauthorized

Request Headers
Accept: */*
Accept-Encoding: gzip,deflate,sdch
Accept-Language: en-US,en;q=0.8,ru;q=0.6
Access-Control-Request-Headers: accept, content-type
Access-Control-Request-Method: POST
Connection: keep-alive
Host: localhost:8082
Origin: http://localhost:8383
Referer: http://localhost:8383/Application/index.html
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/38.0.2125.104 Safari/537.36
X-DevTools-Emulate-Network-Conditions-Client-Id: 49E7FC68-A65C-4318-9292-852946051F27

Response Headers
Cache-Control: private
Content-Length: 6388
Content-Type: text/html; charset=utf-8
Date: Fri, 24 Oct 2014 13:40:07 GMT
Server: Microsoft-IIS/7.5
WWW-Authenticate: Negotiate
NTLM
X-Powered-By: ASP.NET
Run Code Online (Sandbox Code Playgroud)