【发布时间】:2014-12-05 11:13:01
【问题描述】:
从 Chrome 版本 37 开始,如果服务器启用了身份验证,即使所有 CORS 标头都已正确设置,预先发送的跨域请求也会失败(再次)。这是在localhost(我的开发PC)上。
你们中的一些人可能知道 Chrome/CORS/auth 错误的历史,尤其是在涉及 HTTPS 时。我的问题不涉及HTTPS:我有一个AngularJS应用程序从localhost:8383与localhost:8081上的Java(Jetty)服务器交谈,该服务器已激活HTTP BASIC身份验证。 GET 工作正常,但 POST 失败并显示 401:
XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
Invalid HTTP status code 401
我之前编写了一个自定义 (Java) CORS 过滤器,用于设置正确的 CORS 标头,直到 v36。它在 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;
以下是请求/响应。可以看到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"
有人知道我还应该做什么吗?我确保在测试、重新启动之前清除 Chrome 缓存,并确保在重新启动之前没有运行任何后台 Chrome 进程,所以我很确定没有挥之不去的身份验证缓存问题。
我不得不切换到 IE 11 来测试我的 Web 开发。相同的客户端和服务器设置仍然适用于 IE 和 Opera,以及 Chrome/CORS 错误的历史,让我怀疑 Chrome。
编辑:这是 Chrome 网络内部事件列表的摘录:
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
因此,即使我明确设置了withCredentials = true,但授权标头似乎并未与 OPTIONS 预检一起发送。
但是,为什么 IE 和 Opera 仍然可以工作? Chrome 在这方面是否更符合标准?为什么它可以工作,然后从 v37 开始失败?
编辑:Chrome 开发工具没有在上面的转储中显示请求的Content-Type,但这里它来自网络日志。第一张图片显示了禁用服务器身份验证时的 POST,内容类型正确发送为“应用程序/json”。第二张图片是启用身份验证时,显示 OPTIONS 请求失败(似乎 OPTIONS 总是以内容类型“text/plain”发送?)。
【问题讨论】:
-
您仍未显示所有响应标头。您能否也显示对 OPTIONS 请求的完整响应?如果您在开发者工具中看不到它,请访问
chrome://net-internals/#events,然后发出请求,然后返回该 chrome 页面并找到描述您的请求的 URL_REQUEST。 -
当我遇到 CORS 问题时,是因为“内容类型”。而且我在您的查询中没有看到任何内容类型。
-
查看我上面的编辑,显示带有 Content-Type 的网络日志
标签: google-chrome cors