CORS全称“跨站资源共享”(Cross-Origin Resource Sharing),它容许浏览器克服浏览器同源策略向跨域服务器发出请求。html
说到CORS,那么就不得不提浏览器同源策略,所谓“同源”,是指服务器URL的三个相同:web
1.协议相同json
2.域名相同跨域
3.端口相同浏览器
举个栗子:好比一个URL是http://www.example.com:80/a.html
,那么:缓存
http://www.example.com:80/b.html // 同源 https://www.example.com:80/a.html // 非同源(协议不一样) http://www.example1.com:80/a.html // 非同源(域名不一样) http://www.example.com:81/a.html // 非同源(端口不一样)
若是非同源,那么三种行为将受到限制:安全
1.非同源页面没法跨域读取浏览器本地数据存储(Cookie、LocalStorage和IndexDB)服务器
2.非同源页面没法跨域获取DOMwebsocket
3.非同源页面没法跨域发送AJAX请求app
那么,为何浏览器要使用同源策略?
同源策略的目的,是为了保证用户的信息安全,防止被不法分子窃取数据。而众所周知,Cookie包含大量的登陆信息,若是一个网页能够跨域访问另外一个网站的Cookie,那么不法分子能够经过使用跨域访问获取Cookie而后冒充用户,随心所欲。
因而可知,同源策略是极其有必要的。
可是,不少时候,咱们须要跨域发送AJAX请求,此时咱们就须要突破同源策略不容许发送跨域AJAX的规定。随着技术的发展,有不少技术能够实现跨域发送AJAX请求,常见的有如下三种:
1.JSONP
2.Websocket
3.CORS
JSONP是CORS技术出来以前最经常使用的跨域解决方案,最大的特定是兼容性好,简单,不须要进行大的服务器改动。它的基本思路是经过动态添加一个script标签,向服务器请求脚本,脚本中通常调用一个客户端定义的函数,将数据做为参数,调用客户端的函数,而客户端经过操做该函数,可使用被当作参数传过来的数据。
由于服务器不限制script的跨域,因此不受跨域影响。
众所周知,Websocket是一个持久化协议,经常使用于解决服务器推送问题。可是,实际上Websocket其实支持跨域通讯。经过设置Websocket的origin
的字段,能够规定容许跨域的站点。
上面两种方法虽然能够解决跨域,可是,都有着各类问题。
庆幸的是,本文的主角:CORS的出现,完全解决了跨域问题。
浏览器将跨域AJAX请求分为两类:简单请求和非简单请求,对应有两种不一样的处理方式。
何为简单请求?
简单请求就是知足如下两个条件的请求:
1.请求方法为HEAD、GET和POST
2.HTTP请求头只包含:Accept
、Accept-Language
、Content-Language
、Last-Event-ID
以及值为application/x-www-form-urlencoded
、multipart/form-data
、text/plain
三者之一的Content-Type
对于简单请求,浏览器能够直接发送请求到服务器,可是会在请求头中添加一个origin
字段,该字段用来讲明请求的来源。服务器会识别该字段,判断是否容许跨域。
若是容许跨域,服务器会返回结果并在响应头上添加三个字段:
1.Access-Control-Allow-Origin
该字段的值为Origin字段的值,或者是*
,表示服务器接受任何源的跨域请求。
2.Access-Control-Allow-Credentials
可选字段,它表示是否容许发送Cookie,值为true
时,表示发送请求的时候容许发送Cookie,若是不包含该字段,则表示不容许发送Cookie。
值得一提的是,若是服务器容许发送Cookie,那么不容许将Access-Control-Allow-Origin
的值设为*
。
3.Access-Control-Expose-Headers
可选字段,在没有该字段的状况下,针对跨域请求,XHR对象的getResponseHeader()
方法只能拿到Cache-Control
、Content-Language
、Content-Type
、Expire
、Last-Modified
、Pragma
这六个字段,该字段能够设置额外能够拿到的字段。
不知足简单请求的跨域请求都是非简单请求,好比PUT或DELETE方法。
不一样于简单请求的直接向服务器请求,非简单请求会在发送以前,先进行一次“预检”(preflight),即,向服务器发出一个OPTIONS请求,查询服务器是否容许它进行跨域请求。
若是服务器不经过“预检”,会返回一个error,客户端能够经过onerror事件进行捕获。
当服务器经过“预检”后,服务器会进行响应,响应头中含有CORS的相关字段,分别是:
1.Access-Control-Allow-Origin
该字段和简单请求中的同名字段同样。
2.Access-Control-Allow-Methods
该字段表示服务器支持跨域的全部方法,是一个逗号分隔的字符串,如:POST,DELETE。
3.Access-Control-Allow-Headers
该字段表示服务器支持的全部头信息,也是一个逗号分隔的字符串。
4.Access-Control-Allow-Credentials
可选字段,与简单请求中的同名字段同样。
5.Access-Control-Max-Age
可选字段,在一段时间内,浏览器对同一个域名进行非简单跨域请求,只对第一次进行“预检”,而这一次“预检”的结果将被缓存,接下来的请求都经过该结果进行判断。该字段就是用来设置“预检”结果缓存的时间长短,能够将其值设为-1
来禁用“预检”缓存。
接收到服务器经过“预检”的响应后,客户端会正式发送真正的请求,接下来的处理方式和简单请求一致。
在当前开发中,当不须要兼容老式浏览器中,咱们通常采用CORS的方式进行跨域请求,由于相比Websocket,CORS支持非长链接场景;相比JSONP,CORS支持全部HTTP请求,用法更加平滑。
固然,值得一提的是,当你须要兼容老式浏览器时,JSONP是你惟一的选择~