Chrome v37 / 38 CORS失败(再次),其中401用于OPTIONS预飞行请求 [英] Chrome v37/38 CORS failing (again) with 401 for OPTIONS pre-flight requests

查看:303
本文介绍了Chrome v37 / 38 CORS失败(再次),其中401用于OPTIONS预飞行请求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

从Chrome版本37起,如果服务器已启用身份验证,即使所有CORS标头都设置正确,预先投放的跨网域请求也会再次失败。这是 localhost (我的电脑)。



有些人可能知道Chrome / CORS / auth错误,特别是当涉及HTTPS。我的问题不是涉及HTTPS:我有一个AngularJS应用程序从 localhost:8383 提供在Java(Jetty) c> localhost:8081 启用了HTTP BASIC auth。 GETs工作正常,但POSTs失败与401:

  XMLHttpRequest无法加载http:// localhost:8081 / cellnostics / rest /患者。 
HTTP状态代码无效401

我以前写过一个自定义设置正确的CORS头文件,直到v36。它在v37和最新的v38(38.0.2125.101米)失败。



GET 使用Internet Explorer 11(11.0.9600)和Opera 12.17(版本1863) strong>请求成功,但 POST 失败。由于内容类型:application / json,Chrome浏览器似乎已预先排期我的所有POST,并且它是预先排定的OPTIONS请求失败。



在Angular应用中,我显式设置了以下请求标头。 AFAIK此设置为 withCredentials 应该确保即使对于OPTIONS请求也发送凭据:

  //启用跨域调用
$ httpProvider.defaults.useXDomain = true;

//使用凭证发送所有请求,甚至OPTIONS
$ httpProvider.defaults.withCredentials = true;

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



远程地址:[:: 1]:8081
请求URL:http:// localhost:8081 / cellnostics / rest / medicaltest
请求方法:选项
状态代码:401需要完全身份验证才能访问此资源

请求标题:

接受:* / *
Accept-编码:gzip,deflate,sdch
Accept-Language:en-US,en; q = 0.8,af; q = 0.6
访问控制请求头:accept,content-type
访问控制请求方法:POST
连接:keep-alive
主机:localhost:8081
原产地:http:// localhost:8383
参考:http: /localhost:8383/celln-web/index.html
User-Agent:Mozilla / 5.0(Windows NT 6.1; WOW64)AppleWebKit / 537.36(KHTML,像Gecko)Chrome / 38.0.2125.101 Safari / 537.36

响应头:

访问控制允许标识符:true
访问控制允许标头:高速缓存控制,原语,原始,授权,内容类型,X-Requested-With,Accept
访问控制允许方法:POST,GET,OPTIONS,PUT,DELETE
访问控制允许原因:http:// localhost:8383
Access-Control-Max-Age:3600
Content-Length:0
服务器:Jetty(8.1.8.v20121106)
WWW验证:Basic realm =Cellnostics

有没有人知道我还应该做什么?我确保在测试,重新启动之前清除Chrome缓存,并确保没有后台Chrome进程在重新启动之前仍然运行,所以我很确定没有遗留的身份验证缓存问题。



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



EDIT:以下是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
连接:keep-alive
访问控制请求方法:POST
原产地:http: / localhost:8383
用户代理:Mozilla / 5.0(Windows NT 6.1; WOW64)AppleWebKit / 537.36(KHTML,像Gecko)Chrome / 38.0.2125.101 Safari / 537.36
访问控制请求标头: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

因此,看起来授权头不会与OPTIONS预发送一起发送,即使我显式设置 withCredentials = true



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



编辑:Chrome开发工具不显示 Content-Type 的请求在上面的转储,但这里是从网络日志。第一个图片显示了禁用服务器身份验证时的POST,内容类型正确地作为application / json发送。第二个图片是在启用auth时显示OPTIONS请求失败(似乎OPTIONS总是与内容类型text / plain一起发送?)




解决方案

@Cornel Masson问题?我不明白为什么您的服务器要求您验证OPTIONS请求,但是我面临的这个问题针对SAP NetWeaver服务器。



关于你的句子






$ b


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





  • a href =http://www.w3.org/TR/cors/#preflight-request =nofollow> CORS规范,当用户代理(因此,浏览器)预先提出请求时(请求与OPTIONS HTTP方法),它必须排除用户凭据(Cookie,HTTP身份验证...),因此任何OPTIONS请求不能请求作为身份验证。浏览器将请求认证的实际请求(具有请求的HTTP方法,例如GET,POST ...的请求),但不是预检请求。

  • 因此浏览器不得发送凭证在OPTIONS请求中。他们将在实际请求中做。如果你写 withCredentials = true 浏览器应该做我说的话。



根据你的句子: / p>


由于内容类型:application / json,Chrome浏览器似乎预先放送了所有的POST:



  • 该规范还说,浏览器会在标题不是简单头,这里你有什么意思:


    如果头字段名是ASCII字段, - 对于Accept,Accept-Language或Content-Language的非敏感匹配,或者如果它对于Content-Type和报头字段值媒体类型(不包括参数)是ASCII不区分大小写的匹配,则对于应用程序/ x-www-form-urlencoded multipart / form-data text / plain




如果任何人找到解决方案,我们将不胜感激。


编辑:我刚找到一个有相同问题的人反映真正的问题,与他一样的服务器,你会幸运, https://evolpin.wordpress。 com / 2012/10/12 / the-cors /


As from Chrome version 37, pre-flighted, cross-domain requests are failing (again) if the server has authentication enabled, even though all CORS headers are set correctly. This is on localhost (my dev PC).

Some of you may be aware of the history of Chrome/CORS/auth bugs, especially when HTTPS was involved. My problem does not involve HTTPS: I have an AngularJS application served from localhost:8383 talking to a Java (Jetty) server on localhost:8081 that has HTTP BASIC auth activated. GETs work fine, but POSTs fail with a 401:

XMLHttpRequest cannot load http://localhost:8081/cellnostics/rest/patient.
Invalid HTTP status code 401

I have previously written a custom (Java) CORS filter that sets the correct CORS headers, which worked up until v36. It fails in v37 and also the latest v38 (38.0.2125.101 m). It still works as expected with Internet Explorer 11 (11.0.9600) and Opera 12.17 (build 1863).

GET requests succeed, but POSTs fail. It looks like Chrome is pre-flighting all my POSTs due to the content-type: "application/json", and that it is the pre-flighted OPTIONS request that is failing.

In the Angular app I explicitly set the following request headers. AFAIK this setting for withCredentials should ensure that credentials are sent even for OPTIONS requests:

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

//Send all requests, even OPTIONS, with credentials
$httpProvider.defaults.withCredentials = true;

Below is the request/response. You can see that the OPTIONS method is enabled in the Access-Control-Allow-Methods header. You can also see that the Javascript app's origin is explicitly enabled: 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"

Has anyone got any idea what else I should do? I made sure to clear the Chrome cache before testing, restarting and ensuring that there were no background Chrome processes left running before restart, so I'm pretty sure that there were no lingering auth cache issues.

I've had to switch to IE 11 for testing my web development. The fact that the same client and server setup still works for IE and Opera, and the fact that there is a history of Chrome/CORS bugs, makes me suspect Chrome.

EDIT: Here's an extract from the Chrome net-internals event list:

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

So it looks like the Authorization header is not sent with the OPTIONS pre-flight, even though I explicitly set withCredentials = true.

However, why would IE and Opera still work? Is Chrome more standards-compliant in this regard? Why did it work and then start failing from v37?

EDIT: Chrome dev tools does not show the Content-Type of the request in the dumps above, but here it is from the Network log. The first pic shows the POST when the server auth is disabled, with content type correctly sent as 'application/json'. The 2nd pic is when the auth is enabled, showing the OPTIONS request failing (it seems OPTIONS is always sent with content type 'text/plain'?).

解决方案

@Cornel Masson, did you solve the problem? I do not understand why your server is asking you to authenticate the OPTIONS request, but I am facing this same issue against a SAP NetWeaver server. I have read the whole CORS specification (I recommend) so I can clarify you some of your doubts.

About your sentence

In the Angular app I explicitly set the following request headers. AFAIK this setting for withCredentials should ensure that credentials are sent even for OPTIONS requests:

  • According to the CORS specification when a user agent (thus, a browser) preflights a request (requests with OPTIONS HTTP method), it MUST exclude the user credentials (cookies, HTTP authentication...) so any OPTIONS request cannot be requested as authenticated. The browser will request as authenticated the actual request (the one with the requested HTTP method like GET, POST...), but not the preflight request.
  • So browsers MUST not send the credentials in OPTIONS request. They will do in actual requests. If you write withCredentials = true the browser should do what I say.

According to your sentence:

It looks like Chrome is pre-flighting all my POSTs due to the content-type: "application/json":

  • The specification also says that a preflight request will be made by the browser when the header is not a "simple header" and here you have what that means:

    A header is said to be a simple header if the header field name is an ASCII case-insensitive match for Accept, Accept-Language, or Content-Language or if it is an ASCII case-insensitive match for Content-Type and the header field value media type (excluding parameters) is an ASCII case-insensitive match for application/x-www-form-urlencoded, multipart/form-data, or text/plain.

  • application/json is not included so the browser MUST preflight the request as it does.
If anyone finds a solution it would be appreciated.

EDIT: I just found a person with same problem that reflects the real problems, and if you uses the same server as him you will be lucky, https://evolpin.wordpress.com/2012/10/12/the-cors/

这篇关于Chrome v37 / 38 CORS失败(再次),其中401用于OPTIONS预飞行请求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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