含义
1995年,同源政策 由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个策略。
最初,它的含义是指,A网站设置的 Cookie,B网站不能打开,除非这两个网站 同源。
所谓 同源 指的是 三个相同:
- 协议相同
- 域名相同
- 端口相同
举例来说,http://www.example.com/dir/page.html
这个网址,
- 协议是
http://
- 域名是
www.example.com
- 端口是
80
(默认端口可以省略)
它的同源网址如下:
http://www.example.com/dir2/other.html
:同源http://example.com/dir/other.html
:不同源(域名不同)http://v2.www.example.com/dir/other.html
:不同源(域名不同)http://www.example.com:81/dir/other.html
:不同源(端口不同)
目的
同源政策的目的,是为了 保证用户信息的安全,防止恶意的网站窃取数据。
设想这样一种情况:A网站是一家银行,用户登录以后,又去浏览其他网站。如果其他网站可以读取A网站的 Cookie,会发生什么?
很显然,如果 Cookie 包含隐私(比如存款总额),这些信息就会泄漏。更可怕的是,Cookie 往往用来保存用户的登录状态,如果用户没有退出登录,其他网站就可以冒充用户,为所欲为。因为浏览器同时还规定,提交表单不受同源政策的限制。
由此可见,”同源政策”是必需的,否则 Cookie 可以共享,互联网就毫无安全可言了。
限制范围
随着互联网的发展,同源政策 越来越严格。目前,如果非同源,有三种行为受到限制:
AJAX 请求不能发送。
Cookie、LocalStorage 和 IndexDB 无法读取。
DOM 无法获得。
虽然这些限制是必要的,但是有时很不方便,合理的用途也受到影响。
跨域-让AJAX不受限制
同源政策规定,AJAX请求只能发给同源的网址,否则就报错。
有三种方法规避这个限制:
CORS
CORS是跨源资源分享(Cross-Origin Resource Sharing)的缩写。它是W3C标准,是跨源AJAX请求的根本解决方法,允许任何类型的请求。nginx反向代理
JSONP
CORS
CORS(Cross-origin resource sharing,跨域资源共享)是一个 W3C 标准,定义了在必须访问跨域资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的 HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
CORS 需要 浏览器 和 服务器 同时支持。目前,所有浏览器都支持该功能,IE 浏览器不能低于 IE10。
整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。
两种请求
浏览器将CORS请求分成两类:简单请求(simple request) 和 非简单请求(not-so-simple request)。
简单请求
同时满足以下条件,就属于简单请求:
请求方法是以下三种方法之一:
- HEAD
- GET
- POST
HTTP的头信息不超出以下几种字段:
- Accept
- Accept-Language
- Content-Language
- Last-Event-ID
- Content-Type:只限于三个值 application/x-www-form-urlencoded、multipart/form-data、text/plain
Content-Type只能取以下几个值:
- application/x-www-form-urlencoded
- multipart/form-data
- text/plain
执行流程
在请求中需要附加一个额外的 Origin 头部,其中包含请求页面的源信息(协议、域名和端口),以便服务器根据这个头部信息来决定是否给予响应。例如:
Origin: http://www.laixiangran.cn
如果服务器认为这个请求可以接受,就在 Access-Control-Allow-Origin 头部中回发相同的源信息(如果是公共资源,可以回发
*
)。例如:Access-Control-Allow-Origin:http://www.laixiangran.cn
没有这个头部或者有这个头部但源信息不匹配,浏览器就会驳回请求。正常情况下,浏览器会处理请求。
注意:请求和响应都不包含 cookie 。
携带 cookie
浏览器向服务器发送 cookie 信息,需要进行下面操作:
前端:
- ajax 请求需要设置 xhr 的属性
withCredentials
为true
后端:
服务器需要允许cookie,设置响应头
Access-Control-Allow-Credentials: true
设置响应头
Access-Control-Allow-Origin
为*
即可,表示后端服务器允许 任意前端服务器 跨域(不安全)
更安全的做法是:指定 前端服务器域名,如:http://localhost:9528
(末尾不能有符号/
)设置响应头
Access-Control-Allow-Headers
为*
即可
非简单请求
不同时满足上面条件的,就是 非简单请求
比如:
- 请求方法是PUT或DELETE
Content-Type
字段的类型是application/json
,即:发送json数据
执行流程
浏览器在发送真正的请求之前,会先发送一个 Preflight 请求给服务器,这种请求使用
OPTIONS
方法,发送下列头部:Origin:与简单的请求相同。 Access-Control-Request-Method: 请求自身使用的方法。 Access-Control-Request-Headers: (可选)自定义的头部信息,多个头部以逗号分隔。
例如:
Origin: http://www.laixiangran.cn Access-Control-Request-Method: POST Access-Control-Request-Headers: NCZ
发送这个请求后,服务器可以决定是否允许这种类型的请求。服务器通过在响应中发送如下头部与浏览器进行沟通:
Access-Control-Allow-Origin:与简单的请求相同。 Access-Control-Allow-Methods: 允许的方法,多个方法以逗号分隔。 Access-Control-Allow-Headers: 允许的头部,多个方法以逗号分隔。 Access-Control-Max-Age: 应该将这个 Preflight 请求缓存多长时间(以秒表示)。
例如:
Access-Control-Allow-Origin: http://www.laixiangran.cn Access-Control-Allow-Methods: GET, POST Access-Control-Allow-Headers: NCZ Access-Control-Max-Age: 1728000
一旦服务器通过 Preflight 请求允许该请求之后,以后每次浏览器正常的 CORS 请求,就都跟简单请求一样了。
携带cookie
浏览器向服务器发送 cookie 信息,需要进行下面操作:
前端:
- ajax 请求需要设置 xhr 的属性
withCredentials
为true
后端:
服务器需要允许cookie,设置响应头
Access-Control-Allow-Credentials: true
返回的响应头
Access-Control-Allow-Origin
,值不能是*
,应该是 与请求网页一致的域名,如:http://localhost:9528
(末尾不能有符号/
)返回的响应头
Access-Control-Allow-Headers
,值不能是*
,如:access-control-allow-origin, authority, content-type, version-info, X-Requested-With
跨域优缺点
优点
CORS 通信与同源的 AJAX 通信没有差别,代码完全一样,容易维护。
支持所有类型的 HTTP 请求。
缺点
存在兼容性问题,特别是 IE10 以下的浏览器。
第一次发送非简单请求时会多一次请求。
参考:
http://www.ruanyifeng.com/blog/2016/04/same-origin-policy.html
http://www.ruanyifeng.com/blog/2016/04/cors.html
https://www.cnblogs.com/laixiangran/p/9064769.html