跨域资源共享 CORS 详解

来源:互联网 发布:python exit(1) 编辑:程序博客网 时间:2024/06/05 23:53

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

本文详细介绍CORS的内部机制。

(图片说明:摄于阿联酋艾因(Al Ain)的绿洲公园)

一、简介

CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。

二、两种请求

浏览器将CORS请求分成两类:简单请求(simple request)和非简单请求(not-so-simple request)。

只要同时满足以下两大条件,就属于简单请求。

(1) 请求方法是以下三种方法之一:

  • HEAD
  • GET
  • POST

(2)HTTP的头信息不超出以下几种字段:

  • Accept
  • Accept-Language
  • Content-Language
  • Last-Event-ID
  • Content-Type:只限于三个值application/x-www-form-urlencodedmultipart/form-datatext/plain

凡是不同时满足上面两个条件,就属于非简单请求。

浏览器对这两种请求的处理,是不一样的。

三、简单请求

3.1 基本流程

对于简单请求,浏览器直接发出CORS请求。具体来说,就是在头信息之中,增加一个Origin字段。

下面是一个例子,浏览器发现这次跨源AJAX请求是简单请求,就自动在头信息之中,添加一个Origin字段。

GET /cors HTTP/1.1Origin: http://api.bob.comHost: api.alice.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...

上面的头信息中,Origin字段用来说明,本次请求来自哪个源(协议 + 域名 + 端口)。服务器根据这个值,决定是否同意这次请求。

如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段(详见下文),就知道出错了,从而抛出一个错误,被XMLHttpRequestonerror回调函数捕获。注意,这种错误无法通过状态码识别,因为HTTP回应的状态码有可能是200。

如果Origin指定的域名在许可范围内,服务器返回的响应,会多出几个头信息字段。

Access-Control-Allow-Origin: http://api.bob.comAccess-Control-Allow-Credentials: trueAccess-Control-Expose-Headers: FooBarContent-Type: text/html; charset=utf-8

上面的头信息之中,有三个与CORS请求相关的字段,都以Access-Control-开头。

(1)Access-Control-Allow-Origin

该字段是必须的。它的值要么是请求时Origin字段的值,要么是一个*,表示接受任意域名的请求。

(2)Access-Control-Allow-Credentials

该字段可选。它的值是一个布尔值,表示是否允许发送Cookie。默认情况下,Cookie不包括在CORS请求之中。设为true,即表示服务器明确许可,Cookie可以包含在请求中,一起发给服务器。这个值也只能设为true,如果服务器不要浏览器发送Cookie,删除该字段即可。

(3)Access-Control-Expose-Headers

该字段可选。CORS请求时,XMLHttpRequest对象的getResponseHeader()方法只能拿到6个基本字段:Cache-ControlContent-LanguageContent-TypeExpiresLast-ModifiedPragma。如果想拿到其他字段,就必须在Access-Control-Expose-Headers里面指定。上面的例子指定,getResponseHeader('FooBar')可以返回FooBar字段的值。

3.2 withCredentials 属性

上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。

Access-Control-Allow-Credentials: true

另一方面,开发者必须在AJAX请求中打开withCredentials属性。

var xhr = new XMLHttpRequest();xhr.withCredentials = true;

否则,即使服务器同意发送Cookie,浏览器也不会发送。或者,服务器要求设置Cookie,浏览器也不会处理。

但是,如果省略withCredentials设置,有的浏览器还是会一起发送Cookie。这时,可以显式关闭withCredentials

xhr.withCredentials = false;

需要注意的是,如果要发送Cookie,Access-Control-Allow-Origin就不能设为星号,必须指定明确的、与请求网页一致的域名。同时,Cookie依然遵循同源政策,只有用服务器域名设置的Cookie才会上传,其他域名的Cookie并不会上传,且(跨源)原网页代码中的document.cookie也无法读取服务器域名下的Cookie。

四、非简单请求

4.1 预检请求

非简单请求是那种对服务器有特殊要求的请求,比如请求方法是PUTDELETE,或者Content-Type字段的类型是application/json

非简单请求的CORS请求,会在正式通信之前,增加一次HTTP查询请求,称为"预检"请求(preflight)。

浏览器先询问服务器,当前网页所在的域名是否在服务器的许可名单之中,以及可以使用哪些HTTP动词和头信息字段。只有得到肯定答复,浏览器才会发出正式的XMLHttpRequest请求,否则就报错。

下面是一段浏览器的JavaScript脚本。

var url = 'http://api.alice.com/cors';var xhr = new XMLHttpRequest();xhr.open('PUT', url, true);xhr.setRequestHeader('X-Custom-Header', 'value');xhr.send();

上面代码中,HTTP请求的方法是PUT,并且发送一个自定义头信息X-Custom-Header

浏览器发现,这是一个非简单请求,就自动发出一个"预检"请求,要求服务器确认可以这样请求。下面是这个"预检"请求的HTTP头信息。

OPTIONS /cors HTTP/1.1Origin: http://api.bob.comAccess-Control-Request-Method: PUTAccess-Control-Request-Headers: X-Custom-HeaderHost: api.alice.comAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...

"预检"请求用的请求方法是OPTIONS,表示这个请求是用来询问的。头信息里面,关键字段是Origin,表示请求来自哪个源。

除了Origin字段,"预检"请求的头信息包括两个特殊字段。

(1)Access-Control-Request-Method

该字段是必须的,用来列出浏览器的CORS请求会用到哪些HTTP方法,上例是PUT

(2)Access-Control-Request-Headers

该字段是一个逗号分隔的字符串,指定浏览器CORS请求会额外发送的头信息字段,上例是X-Custom-Header

4.2 预检请求的回应

服务器收到"预检"请求以后,检查了OriginAccess-Control-Request-MethodAccess-Control-Request-Headers字段以后,确认允许跨源请求,就可以做出回应。

HTTP/1.1 200 OKDate: Mon, 01 Dec 2008 01:15:39 GMTServer: Apache/2.0.61 (Unix)Access-Control-Allow-Origin: http://api.bob.comAccess-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderContent-Type: text/html; charset=utf-8Content-Encoding: gzipContent-Length: 0Keep-Alive: timeout=2, max=100Connection: Keep-AliveContent-Type: text/plain

上面的HTTP回应中,关键的是Access-Control-Allow-Origin字段,表示http://api.bob.com可以请求数据。该字段也可以设为星号,表示同意任意跨源请求。

Access-Control-Allow-Origin: *

如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段。这时,浏览器就会认定,服务器不同意预检请求,因此触发一个错误,被XMLHttpRequest对象的onerror回调函数捕获。控制台会打印出如下的报错信息。

XMLHttpRequest cannot load http://api.alice.com.Origin http://api.bob.com is not allowed by Access-Control-Allow-Origin.

服务器回应的其他CORS相关字段如下。

Access-Control-Allow-Methods: GET, POST, PUTAccess-Control-Allow-Headers: X-Custom-HeaderAccess-Control-Allow-Credentials: trueAccess-Control-Max-Age: 1728000

(1)Access-Control-Allow-Methods

该字段必需,它的值是逗号分隔的一个字符串,表明服务器支持的所有跨域请求的方法。注意,返回的是所有支持的方法,而不单是浏览器请求的那个方法。这是为了避免多次"预检"请求。

(2)Access-Control-Allow-Headers

如果浏览器请求包括Access-Control-Request-Headers字段,则Access-Control-Allow-Headers字段是必需的。它也是一个逗号分隔的字符串,表明服务器支持的所有头信息字段,不限于浏览器在"预检"中请求的字段。

(3)Access-Control-Allow-Credentials

该字段与简单请求时的含义相同。

(4)Access-Control-Max-Age

该字段可选,用来指定本次预检请求的有效期,单位为秒。上面结果中,有效期是20天(1728000秒),即允许缓存该条回应1728000秒(即20天),在此期间,不用发出另一条预检请求。

4.3 浏览器的正常请求和回应

一旦服务器通过了"预检"请求,以后每次浏览器正常的CORS请求,就都跟简单请求一样,会有一个Origin头信息字段。服务器的回应,也都会有一个Access-Control-Allow-Origin头信息字段。

下面是"预检"请求之后,浏览器的正常CORS请求。

PUT /cors HTTP/1.1Origin: http://api.bob.comHost: api.alice.comX-Custom-Header: valueAccept-Language: en-USConnection: keep-aliveUser-Agent: Mozilla/5.0...

上面头信息的Origin字段是浏览器自动添加的。

下面是服务器正常的回应。

Access-Control-Allow-Origin: http://api.bob.comContent-Type: text/html; charset=utf-8

上面头信息中,Access-Control-Allow-Origin字段是每次回应都必定包含的。

五、与JSONP的比较

CORS与JSONP的使用目的相同,但是比JSONP更强大。

JSONP只支持GET请求,CORS支持所有类型的HTTP请求。JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。

(完)

一灯学堂

优达学城

广告(购买广告位)

妙味课堂
腾讯课堂

留言(82条)

阮老师讲得非常全面透彻,看完这篇文章就会对浏览器的同源策略和跨域请求了解清楚了,堪称经典。

asp.net web api 中的坑。
web.config 中 remove name="OPTIONSVerbHandler" 需要去掉。

可以可以,老师这篇文章很关键。但是想多问一句CORS在哪些场景下应用比较多?

正在最近在纠结跨域请求的相关问题,而已有资料的质量良莠不齐,阮一峰老师的两篇博文真的超级赞。

Access-Control-Allow-Origin支持多域名:http://junyi.me/blog/s17.html

文中提到“CORS请求默认不发送Cookie”,通过服务端响应 Access-Control-Allow-Credentials: true 来控制。但如果接口依赖Cookie来完成一些处理(比如登录态),那第一次发送CORS请求“默认不发送Cookie”的话,服务端接受不到Cookie,岂不会有问题?

从实验上来看,Access-Control-Allow-Credentials: true 好像并没有控制Cookie是否发送,因为即使之前没有任何CORS请求(自然也没有往客户端发送该Header),第一次CORS请求也会带上所有该域能访问的Cookie。

测试环境:Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36

@四喜,

我试了一下,如果设为 withCredentials = false ,就不会发送 Cookie 了。如果省略这一行,确实会发送。但 MDN 明确说,默认值是 false。https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/withCredentials

我原来的说法表达得不确切,我改一下。

Access-Control-Allow-Origin 字段,如何表示允许一个以上的网站访问(不是*这种全部),比如 允许 http://api.bob.com、 http://api.alice.com两个网站。

Access-Control-Allow-Origin 字段能实现吗?我这边试下,好像不行。

简单请求的 Content-Type 包含 text/plain 而不是 text/html 感觉不科学啊~

简单请求包含connection首部,但是文中指出的不符?

(2)HTTP的头信息不超出以下几种字段:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

4.2节里有笔误Access-Control-Allow-Headers: true 应该是 Access-Control-Allow-Credentials: true

@张歆琳:

谢谢指出,已经改正了。

如果浏览器否定了"预检"请求,
----
这个应该是『服务器否定了"预检"请求』吧。

写的非常好,感谢阮老师的分享

文章写的非常好,又掌握了一个重要的知识点!感谢阮兄分享

有一个问题想请教一下,在淘宝登陆后,打开天猫,会发现也是已登录状态,这是怎么做的呢?

4.2 节里面,「服务器回应的其他CORS相关字段如下」中,有个字段写错了吧?写了两次「Allow-Headers」。

看阮老师一篇文章,胜读十本书

学习了,两篇文章讲得非常详细,感谢

还有IE的ActiveXObject

受教,谢谢阮老师~

引用大头的发言:

看阮老师一篇文章,胜读十本书

你看书只看序的吧?

引用光君的发言:

可以可以,老师这篇文章很关键。但是想多问一句CORS在哪些场景下应用比较多?

restful api

引用echo的发言:

restful api

有些疑问:
1)为啥看到一些公开的API貌似没有origin 
2)restful api 、 web api 、cors 、web service 目前流行哪个做API呢 
3) cors IE10才可能,兼容性如何解决呢?

关于Credentials,重要的不是会不会发送,而是cookie发送到服务端后如果response header中无Access-Control-Allow-Credentials: true,那么浏览器会报异常,js无法拿到跨域请求的response对象

我的请求:
```
$.ajax({
type: "POST",
url: "http://192.168.0.103:8081/forum/servlet/HelloServlet",
//contentType:"application/json",
data: {uName:$("#uName").val(), uPwd:$("#uPwd").val()},
dataType: "json",
success: function(data){
$('#resText').empty(); // 清空resText里面的所有内容
var html = ''; 
$.each(data, function(commentIndex, comment){
html += '<div class="comment"><h6>' + comment['username']
+ ':</h6>

+ '</p></div>';
});
$('#resText').html(html);
}
});
```

服务端接收到后增加CORS处理。
```
response.setContentType("text/html; charset=utf-8");
response.addHeader("Access-Control-Allow-Origin", "*");
response.addHeader("Access-Control-Allow-Methods", "*");
response.addHeader("Access-Control-Max-Age", "100");
response.addHeader("Access-Control-Allow-Headers", "X-Custom-Header,accept, content-type");
response.addHeader("Access-Control-Allow-Credentials", "false");
```

===========================================
为什么留言不能超过1200个字,接上一个提问
===========================================

不加 `contentType="application/json"`正常访问后台。增加`contentType="application/json"`后提示:
```
XMLHttpRequest cannot load http://192.168.0.103:8081/forum/servlet/HelloServlet. Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://127.0.0.1:8020' is therefore not allowed access.
```
从错误看,应该是preflight (预检)请求涉及到跨域问题了。现在问题是preflight 的请求响应设置在哪边处理呢?

写的超赞!

阮老师想问你个问题,我目前也是在Cors跨域这块遇到了难题,1.我在复杂请求时,PUT,首先预检通过,可以看到status code:200状态码,2.然后第二次要做真实的修改操作,直接报500状态码,服务器内部错误,响应头里面没有Origin,Headers,Method这三项.请问这是什么情况呢?烦请阮老师帮忙看下。不胜感谢!

想问阮老师,跨协议请求有类似的解决方案吗?如http请求https,谢谢。

提一点:
做auth时,xhr.setRequestHeader,key 不能是 token 字符串。

引用光君的发言:

可以可以,老师这篇文章很关键。但是想多问一句CORS在哪些场景下应用比较多?

我们项目目前使用Restful架构,由于前后不在台服务器,处处需跨源

引用Slimmer的发言:


我们项目目前使用Restful架构,由于前后不在台服务器,处处需跨源


我在想,即使不在同一台服务器,如果前台用nginx做请求转发,把不同请求转发到不同服务器,这样,从浏览器的角度来看,域名就没有发生变化,也就不用跨域。我的想法对吗?

Access-Control-Max-Age字段在webkit的浏览器上默认最大时间为5分钟,若设置超过5分钟则不会生效,代码见https://cs.chromium.org/chromium/src/third_party/WebKit/Source/core/loader/CrossOriginPreflightResultCache.cpp?rcl=1399481969&l=44
另外,chrome实际上有bug,即使Access-Control-Max-Age设置为600,下次请求时依然会发送options请求,此bug在2012年被提出,但至今未修复。具体见 https://bugs.chromium.org/p/chromium/issues/detail?id=131368

可以在http://test-cors.org/ 测试

我之前的表述可能有问题。

经过测试,chrome现阶段(54.0.2840.50 beta-m (64-bit))是支持对options的请求缓存5分钟的

我之前之所以会觉得没有缓存,是因为我原以为preflight-result-cache是以域名为单位的cache,但看了https://www.w3.org/TR/cors/#preflight-result-cache 后发现cache是以origin+url+credentials+method+header在max-age内cache的,所以不同url(get参数不同也算的)是会发送多次options请求的

今天正好我女朋友面试,被问到这个问题,我觉得即便是研究生想说透也不是件很容易的事情。

我本人实际项目中倒是遇到过跨域问题,一个业务场景是用户上传图片然后切图后再保存,上传图片到第三方存储后(我用的是aws的s3+cloudfront),前端js类库从cdn获取原图时用的是ajax方法。在s3设置cors策略,在cloudfront设置http预检策略,结合阮老师的文章,基本理解到位了,非常感谢!

在3.1节中您讲到:

> 如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。

请问 许可范围 是在什么地方指定的呢?谢谢!

目前为止看到的最深入浅出的解释!

您好,在测试这个问题的时候,发现即便服务器端不设置Access-Control-Allow-Origin头,服务器依然会返回数据,可以用fiddler抓取到,和设置头信息后的区别只是浏览器页面不显示数据而已。能否表明,CORS设置与否只是影响浏览器是否显示服务器返回的数据,而无法阻止服务器要不要返回数据?

ie8通过XDomainRequest能支持CORS,文中说要不低于ie10,难道我理解错了。

“上面说到,CORS请求默认不发送Cookie和HTTP认证信息。如果要把Cookie发到服务器,一方面要服务器同意,指定Access-Control-Allow-Credentials字段。”

对于简单请求,其并没有预检请求。也就是说收到服务器响应的时候,简单请求已经发出去了,也就是说简单请求发送的时候不管是带不带cookie,这个决策已经完成了。那么这时候server返回Access-Control-Allow-Credentials字段的意义是什么呢?

1. 告诉浏览器其实服务器并没有处理你发送过来的cookie,假设浏览器发了cookie并期待cookie生效以达成某种目的的话,用来帮助定位问题?
2. 告诉浏览器这个信息,下次再发同样的跨域请求的时候就知道该不该发送cookie了?

最近要把web端已有的应用扩展到移动端h5轻应用上,遇到了跨域访问一个诡异的问题。在服务端设置好Access-Control-Allow-Origin:* ;Access-Control-Allow-Credentials: "true" 后,两个系统做了cas,然后开发环境一切ok。等到项目准备上线时,打包进weblogic,居然发现访问失效。具体表现是当请求的结果超出一定数据量以后(因为可以指定每页条数,所以可以一点点的加返回数据量,当到了一个临界值以后,突然出现问题,比如30条的时候没事,31条突然就没数据了),从浏览器观察返回的response为空。在weblogic开了debug模式,发现后端一切正常没有任何错误,也确实查了数据库也确实返回了。后来为了验证这个问题,把同一个包又放到tomcat上跑,发现能返回数据量的临界值更小了,同一个包放在本地jetty上就没这个问题。所以我怀疑是不是各个应用服务器在处理跨域返回数据量时有一个默认值,可以配置的?我找了文档却没发现有这个设置。百思不得其解,卡了我好几个周了,求大神解惑!!!
今天我又做了几个实验,这个限额大约是20k的样子!!

大神,有没有cros跨域请求的具体实例呀?我在使用cros跨域上传文件过程中从后台返回的数据前台接收不到,status是0,急用,麻烦您了

引用Silas的发言:

提一点:
做auth时,xhr.setRequestHeader,key 不能是 token 字符串。

我就遇到了这种问题,angular 拦截器设置了 req.headers['token'] = ‘’; 跨域就无法通过预检测器,请问有什么方法么,我也设置了
res.setHeader('Access-Control-Allow-Headers','token');
但还是无法实现

cors并不是所有浏览器都支持吧,opera mini就是一个例子,现在做这套策略还应该考虑降级问题

Access-Control-Max-Age 在chrome控制台注意有disabled cache的选项,
不然会被坑,我调了很久也不生效,信好网上看到.提醒一下大家.

Access-Control-Request-Method 这个方法是告诉服务端我将要用什么方法请求数据,而不是方法的罗列。
补充withCredentials = true; 设置Access-Control-Allow-Credentials = true的同时Access-Control-Allow-Origin的值不能为“*”,必须设置一个完整的域,只允许一条。

引用cmxz的发言:

关于Credentials,重要的不是会不会发送,而是cookie发送到服务端后如果response header中无Access-Control-Allow-Credentials: true,那么浏览器会报异常,js无法拿到跨域请求的response对象

这么解释看得才明白,文章里说的没理解

引用quay的发言:

有些疑问:
1)为啥看到一些公开的API貌似没有origin
2)restful api、 web api 、cors 、web service 目前流行哪个做API呢
3) cors IE10才可能,兼容性如何解决呢?

1)应该是那些应用有一个后台服务器,后台服务器调用的API
2)restful api 是 web api 中的一种吧 
cors 只要浏览器 xhr 跨域请求都要面对的问题,和什么形式 api 无关 
web service 是很早之前的技术,现在应该是不流行了 
3)JSONP

引用Sia的发言:

有一个问题想请教一下,在淘宝登陆后,打开天猫,会发现也是已登录状态,这是怎么做的呢?

自己感觉是用同一个数据库吧 起码是用户表 订单表 之类的 通用的会有关联

阮老师您好,我测试了一下。。。。在前后端分离的情况下,前端发put的非简单请求,并不能够跨源,这是为什么呢? 后端采用node 接收请求。 
在前后端不分离的情况下,前端发put的非简单请求,是可以跨源的。

引用杨铮的发言:

asp.net web api 中的坑。
web.config 中 remove name="OPTIONSVerbHandler" 需要去掉。

还真碰到这个坑了。

感谢,介绍的很详细。
另外请问,如果返回头里包含两个Access-Control-Allow-Origin符合规范吗?比如返回头同时包含如下两个:
Access-Control-Allow-Origin:www.origin.com //(请求发出域名)
Access-Control-Allow-Origin:*

在实际中遇上过上述问题,后台代码和IIS分别为返回头添加了Access-Control-Allow-Origin。当请求发出域名和接收域名(后台)是同一域名时可正常得到结果,但不是统一域名时就会报跨域错误。
阮老师能帮忙解释一下吗?谢谢

看文章的说法,浏览器决定是否跨域,那么服务端呢?简单的跨域,浏览器带着cookie请求服务器,服务器设置false,则不接收cookie?事实上cookie已经加载到request里了。
第二个问题,简单的跨域中,如果服务端部允许跨域,那么服务端是直接返回空还是按照正常的逻辑返回了数据,只是到浏览器的时候被浏览器给拦截了?

@Ryan:

肯定啊 都是浏览器,如果不是浏览器 就不存在这个问题 比如服务器端程序 想请求谁就请求谁 ,

预检结果
Response Headers
Allow:GET, HEAD, POST, PUT, DELETE, TRACE, OPTIONS, PATCH
Content-Length:0
Date:Fri, 31 Mar 2017 06:12:56 GMT
Request Headers
Accept:*/*
Accept-Encoding:gzip, deflate, sdch
Accept-Language:zh-CN,zh;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:POST
Connection:keep-alive
Host:10.220.17.121:8080
Origin:http://10.220.18.113:8020
Referer:http://10.220.18.113:8020/xb/wx/201703013/login.html
User-Agent:Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Mobile Safari/537.36
如何让浏览器通过Origin呢 怎么设置?

我只能说,相见恨晚呐!看了几篇阮老师的博客下来,发现内容讲解都非常细致,很难找到比阮老师的更适合初学者的教程了。

关于JSONP,“JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据”。支持老式浏览器是确实是其优势,但像不支持CORS的网站请求数据,我觉得就不是它的优势了,因为后端代码还是得针对JSONP做出相应的调整(返回json字符串的部分需要用传过去的回调函数名包起来),也很麻烦。反而CORS的方式,只需要在后端代码的过滤器上加上相应的响应头就行了,来得更方便。

阮老师,感谢您的文章。现在有一些不明白的地方希望跟你请教一下:
服务器对于预检请求和实际请求是需要用不同的方法去拦截吗?还是这两个请求都是由同一个方法去处理的


https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Access_control_CORS

这里找到答案了:
“因为这是一个简单 GET 请求,所以浏览器不会对其发起“预检请求”。但是,如果服务器端的响应中未携带 Access-Control-Allow-Credentials: true ,浏览器将不会把响应内容返回给请求的发送者。”

阮老师,3.1节中,【如果Origin指定的源,不在许可范围内,服务器会返回一个正常的HTTP回应。浏览器发现,这个回应的头信息没有包含Access-Control-Allow-Origin字段】,这句话有误吧?如果Origin源不在指定的许可范围内,回应的头信息也会包含Access-Control-Allow-Origin字段吧,只是它的值与Origin源不匹配,就会执行onerror错误事件驱动程序

一个post跨域请求在“预检”请求OPTIONS中Origin为什么会为null,并且会报错:

Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access. The response had HTTP status code 401.

OPTIONS请求http头部信息如下:

Accept:*/*
Accept-Encoding:gzip, deflate, sdch, br
Accept-Language:zh-CN,zh;q=0.8
Access-Control-Request-Headers:authorization
Access-Control-Request-Method:POST
Connection:keep-alive
Host:chinapopin.com
Origin:null
User-Agent:Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.96 Safari/537.36

引用严泽玮的发言:

ie8通过XDomainRequest能支持CORS,文中说要不低于ie10,难道我理解错了。

xDomainRequest 只支持post,get 不给带cookie等等 大多数情况下等于没什么用

厉害了 阮老师,收获很多

阮老师,这样看来,跨域始终都需要服务端支持才能实现对吗? 并不只是纯粹前端设置就能成功的吗?

真心厉害,还是老师讲的简单易懂,一点就通!

没看懂 谁来教下我 前端和node 怎么设置?

引用茉莉的发言:

自己感觉是用同一个数据库吧 起码是用户表 订单表 之类的 通用的会有关联

应该是通过CAS做的单点登录认证(SSO)

怎么有这么好的文章,结合工作中的实践,让我对CORS有了非常清楚的认识。

引用杨铮的发言:

asp.net web api 中的坑。
web.config 中 remove name="OPTIONSVerbHandler" 需要去掉。

这真是绝世大坑!我搞了两天,查了无数资料,竟然有那么多网站说要把OPTIONSVerbHandler和WebDAV删除,事实上把OPTIONSVerbHandler删除了才会造成OPTIONS失败!
难道是部分环境下会这样?

总结一下我的解决方案(IIS10 + asp.net web api):
1、IIS中增加响应头
Access-Control-Allow-Origin:*
Access-Control-Allow-Headers:Content-Type
2、web.config中把“<remove name="OPTIONSVerbHandler" />”删掉

仅此而已~

post请求变成了options,请问该怎么设置呢?

我按照上面配置的,怎么还报这个错误,求指教
Refused to set unsafe header "Access-Control-Request-Method"

复杂请求Content-Type必须为application/json吗还是可以为其他的

IE10以下怎么办

恍然大悟,学习了!

如果浏览器否定了"预检"请求,会返回一个正常的HTTP回应,但是没有任何CORS相关的头信息字段


这里应该是 服务器否定了预检请求吧。

请教下,如果服务器否定了预检请求,那应该返回什么呢? 状态码应该是403还是200?是否继续往下执行程序?谢谢

想请教阮大大关于cors跨域的安全问题,Access-Control-Allow-Origin限定了域名的情况下,还会有什么安全问题呢?

ajax不就是用xmlhttprequest实现的吗 为何单拿出来ajax

不对啊!前一个文章里您是这么说的。
“同源政策规定,AJAX请求只能发给同源的网址,否则就报错。”

按您的说法,跨域了就直接报错了,怎么会发出去呢?

而且我自己实验了一下,我们公司的接口都是可以跨域的,访问方法和平时发送ajax请求没区别。

所以是不是所谓跨域不能请求ajax指的是,后端通过Access-Control-Allow-Origin来限制跨域请求,而不是浏览器限制你发送ajax跨域请求?

cors简单请求不是说不能超过下面的字段么:
Accept
Accept-Language
Content-Language
Last-Event-ID
Content-Type:只限于三个值application/x-www-form-urlencoded、multipart/form-data、text/plain

第一个简单请求的例子中就有
Host
Connection
User-Agent
这些都不再上面的字段中啊, 怎么理解阮大神说的 不能超过如下字段

老师啊, 我前端端口是8699,后台端口是8088,后台登录请求里面设置cookie是不是设置不了啊?为什么下次后台读取cookie的时候,读取不到cookie

干货充足,没有太多的废话,赞^32!
原创粉丝点击