从Chrome版本37开始,如果服务器启用了身份验证,即使已正确设置所有CORS标头,预先发布的跨域请求也会失败(再次)。这是localhost
(我的开发PC)。
有些人可能知道Chrome / CORS / auth错误的历史,特别是涉及HTTPS时。我的问题不涉及HTTPS:我有一个AngularJS应用程序从localhost:8383
与localhost:8081
上的Java(Jetty)服务器通信,该服务器已激活HTTP BASIC auth。 GET工作正常,但POST失败了401:
XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
Invalid HTTP status code 401
我之前编写了一个自定义(Java)CORS过滤器,它设置了正确的CORS标头,直到第36版。它在v37和最新的v38(38.0.2125.101 m)中失败。使用Internet Explorer 11(11.0.9600)和Opera 12.17(版本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来测试我的网站开发。事实上,相同的客户端和服务器设置仍适用于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
因此,即使我明确设置了withCredentials = true
,看起来似乎没有使用OPTIONS运行前发送Authorization标头。
然而,为什么IE和Opera仍然有效? Chrome在这方面是否更符合标准?为什么它会起作用然后从v37开始失败?
编辑:Chrome开发者工具不会在上面的转储中显示请求的Content-Type
,但此处来自网络日志。第一张图片显示禁用服务器身份验证时的POST,内容类型正确发送为'application / json'。第二张图片是启用身份验证时,显示OPTIONS请求失败(似乎OPTIONS总是以内容类型'text / plain'发送?)。
答案 0 :(得分:7)
关于你的句子
在Angular应用程序中,我明确设置了以下请求标头。 AFAIK withCredentials的此设置应确保即使对于OPTIONS请求也会发送凭据:
根据你的判决:
由于内容类型的原因,Chrome看起来像是在推广我的所有POST:" application / json":
如果头字段名称是对Accept,Accept-Language或Content-Language的ASCII不区分大小写的匹配,或者如果它是Content-Type的ASCII不区分大小写的匹配,则称头是简单头标题字段值媒体类型(不包括参数)是 application / x-www-form-urlencoded , multipart / form-data 或<的ASCII不区分大小写的匹配项强>文本/纯强>
编辑:我刚发现一个有相同问题的人反映了真正的问题,如果你使用与他相同的服务器,你会很幸运,https://evolpin.wordpress.com/2012/10/12/the-cors/
答案 1 :(得分:2)
同样在这里。我使用Windows NTLM身份验证。直到Chrome版本37,它工作正常。在版本37,38上,由于在PUT和POST上的飞行前OPTIONS中缺少请求授权头,因此401(未授权)失败。
服务器端是Microsoft Web Api 2.1。我尝试了各种CORS,包括微软最新的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
答案 2 :(得分:2)
在MS IIS上,我通过覆盖Microsoft标准页面生命周期实现了另一种解决方法,即在global.ascx中的HTTP请求开头处理OPTIONS:
public class Global : HttpApplication
{
/// <summary>Check and cofigure CORS Pre-flight request on Begin Request lifecycle
/// </summary>
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains(CorsHandler.Origin) && Request.HttpMethod == "OPTIONS")
{
Response.StatusCode = (int)HttpStatusCode.OK;
Response.Headers.Add(CorsHandler.AccessControlAllowCredentials, "true");
Response.Headers.Add(CorsHandler.AccessControlAllowOrigin, Request.Headers.GetValues(CorsHandler.Origin).First());
string accessControlRequestMethod = Request.Headers.GetValues(CorsHandler.AccessControlRequestMethod).FirstOrDefault();
if (accessControlRequestMethod != null)
{
Response.Headers.Add(CorsHandler.AccessControlAllowMethods, accessControlRequestMethod);
}
var hdrs = Request.Headers.GetValues(CorsHandler.AccessControlRequestHeaders).ToList();
hdrs.Add("X-Auth-Token");
string requestedHeaders = string.Join(", ", hdrs.ToArray());
Response.Headers.Add(CorsHandler.AccessControlAllowHeaders, requestedHeaders);
Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token");
Response.Flush();
}
}
}
答案 3 :(得分:2)
在尝试调试在localhost:4200(使用Angular CLI Live Development Server)上运行的Angular 4前端应用程序时,我们遇到了同样的问题。 Angular应用程序向使用Windows身份验证的localhost(IIS Web服务器)上运行的ASP .Net WebApi2应用程序发出http请求。只有在Chrome中发出POST请求时才会出现此问题(即使我们的WebApi是为COR配置的)。我们能够通过启动Fiddler并运行反向代理来暂时解决问题,直到找到这篇文章(谢谢)。
Chrome调试器中的错误消息: 对预检请求的响应未通过访问控制检查:请求的资源上没有“Access-Control-Allow-Origin”标头
将以下代码添加到我们的Web Api2 - Global.asax文件中解决了这个问题。
如果您正在寻找“CorsHandler”,您只需使用硬编码的字符串值替换George的帖子,如下所示:
protected void Application_BeginRequest()
{
if (Request.Headers.AllKeys.Contains("Origin") && Request.HttpMethod == "OPTIONS")
{
Response.StatusCode = (int)HttpStatusCode.OK;
Response.Headers.Add("Access-Control-Allow-Credentials", "true");
Response.Headers.Add("Access-Control-Allow-Origin", Request.Headers.GetValues("Origin").First());
string accessControlRequestMethod = Request.Headers.GetValues("Access-Control-Request-Method").FirstOrDefault();
if (accessControlRequestMethod != null)
{
Response.Headers.Add("Access-Control-Allow-Methods", accessControlRequestMethod);
}
var hdrs = Request.Headers.GetValues("Access-Control-Request-Headers").ToList();
hdrs.Add("X-Auth-Token");
string requestedHeaders = string.Join(", ", hdrs.ToArray());
Response.Headers.Add("Access-Control-Allow-Headers", requestedHeaders);
Response.Headers.Add("Access-Control-Expose-Headers", "X-Auth-Token");
Response.Flush();
}
}
亲切的问候,
克里斯