跨域资源共享(CORS,英文全称[Cross-Origin Resource Sharing]),基本思路就是使用自定义的 HTTP 头部,允许浏览器和服务器相互了解,以确定请求或响应应该成功还是失败。
同源策略
浏览器的安全基石是“同源策略”,它是浏览器最核心也最基本的安全功能。
同源策略的目的:为了保护用户信息的安全,防止恶意的网站窃取数据。
同源策略的限制:
Cookie
、LocalStorage
、IndexDB
无法读取。DOM
无法获得。Ajax
请求发送后,结果被浏览器拦截了。
所谓“同源”,指的就是“协议”、“域名”和“端口”三者都相同。
下面的表格将举例说明哪些属于同源,哪些属于非同源。
跨域
什么是跨域呢?
跨域就是指向非同源地址,跨域请求就是向非同源地址发送请求。
默认情况下,Ajax
只能向同源地址发送请求,但它发送跨域请求时,并不是请求不能发送出去,而是请求能够发送出去,服务器端也能接收到请求并正常返回结果,只是结果被浏览器拦截了。
跨域解决方案
JSONP
HTML
中有三个允许跨域加载资源的标签:
<img src="" alt="">
<link rel="stylesheet" href="">
<script src=""></script>
JSONP
正是利用 script
标签可以跨域加载资源这一特性,从其他源获取 JSON
数据;JSONP
需要服务器做支持才可以。
JSONP 的优点: 简单易用,兼容性好。
JSONP 的缺点:
- 只支持
GET
方式的请求,具有局限性; - 由于是从不同的域拉取可执行代码,可能会遭受
XSS
攻击; - 不好确定
JSONP
请求是否失败。
CORS
CORS 原理解析
简单请求:
对于简单的请求,即没有自定义头部的 GET
或者 POST
请求,并且它的请求体是 text/plain
类型。这样的请求在发送时,浏览器会添加一个额外的头部,叫 Origin
,它包含发送请求的页面的源(协议、域名和端口),服务器会根据这个 Origin
中的值,决定是否同意这次请求。
如:
Origin: http://www.nczonline.net
如果服务器决定响应该请求,那么这个回应的头信息中应该发送 Access-Control-Allow—Origin
,包含相同的源或者 "*"
(资源是公开的)。
非简单请求:
对于非简单请求的CORS
请求,在正式通信之前,会先向服务器发送一个“预检”请求。
预检请求使用 OPTIONS
方法发送并包含了以下头部:
Origin: http://api.bob.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: X-Custom-Header
Origin
:发送请求的页面的源(协议、域名和端口);Access-Control-Request-Method
:请求希望使用的方法;Access-Control-Request-Headers
:[可选]该字段是一个逗号分隔的字符串,指定浏览器CORS
请求会额外发送的头信息字段。
在预检请求发送后,服务器可以确定是否允许这种类型的请求,确认允许请求,就可以做出回应。服务器会通过在响应中发送如下头部来与浏览器沟通:
Access-Control-Allow-Origin: http://api.bob.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: X-Custom-Header
Access-Control-Max-Age: 1728000
Access-Control-Allow-Origin
:包含与请求的页面相同的源(协议、域名和端口)或者"*"
;Access-Control-Allow-Methods
:允许的方法;Access-Control-Request-Headers
:服务器允许的头部;Access-Control-Max-Age
:缓存预检请求的秒数(即20天);
Access-Control-Max-Age
:该字段可选,如果设置了该项,预检请求返回后,结果会按响应指定的时间缓存一段时间。换句话说,就是在有效期内,之后的请求不需要发送预检请求。
一旦服务器通过了预检请求,以后每次浏览器正常的 CORS
请求,就都跟简单请求一样。
CORS
支持所有类型的 HTTP
请求,是跨域 HTTP
请求的根本解决方案,比 JSONP
的方式更强大。