跨域
什么是跨域?
当不同源进行资源交互时,由于浏览器同源策略的限制而无法正常进行,就产生了跨域问题。
浏览器的同源策略
同源策略是一个重要的安全策略,它用于限制一个源的文档或者它加载的脚本如何能与另一个源的资源进行交互,默认阻止“跨域”获取资源。
同源策略由浏览器来执行,所有的限制都是浏览器的作用,这是浏览器为了保护用户的数据安全而采取的策略。
怎样才算是不同源?
协议、域名、端口这三者任一不同,就是不同源。例如相对于 http://www.abc.com/index.html
页面的同源检测:
URL | 是否同源 | 原因 |
---|---|---|
http://www.abc.com/a.html |
是 | 同源(协议、域名、端口相同) |
https://www.abc.com/index.html |
否 | 协议不同(http 与https ) |
http://www.def.com/index.html |
否 | 域名不同(www.abc.com 与www.def.com ) |
http://www.abc.com:3001/index.html |
否 | 端口不同(默认的80端口 与3001端口 ) |
http://www.abc.com:80/index.html |
是 | 同源(协议、域名、端口相同) |
不同源会怎样?
- 无法用 js 读取非同源的 Cookie、LocalStorage 和 IndexDB 无法读取。
- 无法用 js 获取非同源的 DOM。
- 无法用 js 发送非同源的 AJAX 请求。更准确的说,js 可以向非同源的服务器发请求,但是服务器返回的数据会被浏览器拦截。
前后端通信方式
- Ajax 支持同源通信
- WebSocket 不受同源策略影响
- CORS 既支持同源通信也支持跨域通信
跨域通信的几种方式
1. JSONP
通过 script 标签的异步加载实现,利用 script 标签不受同源策略的限制,天然可以跨域的特性
2. Hash
url # 后面的内容就叫 Hash。Hash 改变,页面不会刷新
3. postMessage
4. WebSocket
WebSocket protocol 是 HTML5 一种新的协议,它实现了浏览器与服务器全双工通信,同时允许跨域通讯,是 server push 技术的一种很好的实现
5. CORS(Cross-Origin Resource Sharing)
现代浏览器普遍跨域解决方案。
整个 CORS 通信过程都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨域,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。因此,实现 CORS 通信的关键是服务器,只要服务器实现了 CORS 接口,就可以跨域通信。
CORS 需要浏览器和服务端同时支持。IE 8 和 9 需要通过 XSDomainRequest 来实现。
通过这种方式解决跨域问题,会在发送请求的时候出现两种情况,分别为 简单请求 和 复杂请求。
什么是 简单请求、复杂请求?
1. 简单请求
只要同时满足以下两大条件,就属于简单请求:
(1)使用下列方法之一:
- GET
- HEAD
- POST
(2)Content-Type 的值仅限于以下三者之一:
- text / plain
- multipart / form-data
- application / x-www-form-urlencoded
请求中的任意 XMLHttpRequestUpload 对象均没有注册任何事件监听器;
XMLHttpRequestUpload 对象可以使用 XMLHttpRequest.upload 属性访问。
2. 复杂请求
不符合以上条件的就是复杂请求。复杂请求的 CORS 请求,会在正式通信之前,增加一次 HTTP 查询请求,称为 预检请求 ,该请求的方法是 Option,通过该请求来查询服务端是否允许跨域请求。
服务端实现 CORS 的方式
Node.JS
// 以 express 为例
app.all('*', function(req, res, next) {
res.header('Access-Control-Allow-Origin', '*')
res.header('Access-Control-Allow-Headers', 'X-Requested-With')
res.header('Access-Control-Allow-Methods', 'PUT,POST,GET,DELETE,OPTIONS')
next()
})
Nginx
server {
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Origin $http_origin;
location /file {
if($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin;
add_header Access-Control-Allow-Methods $http_access_control_request_methods;
add_header Access-Control-Allow-Credentials true;
add_header Access-Control-Allow-Headers $http_access_control_request_headers;
add_header Access-Control-Max-Age 1728000;
return 204;
}
}
}
关键词
跨域、浏览器的同源策略、跨域通信方式、CORS、简单请求、复杂请求
参考
- https://developer.mozilla.org/zh-CN/docs/Web/Security/Same-origin_policy
- https://developer.mozilla.org/zh-CN/docs/Glossary/CORS
- https://developer.mozilla.org/zh-CN/docs/Web/HTTP/CORS
- https://i-want-offer.github.io/FE-Essay/前后端通信/跨域.html#服务端实现-cors-的方式
- https://mp.weixin.qq.com/s/0NzfGDvJMAlE2zpT-KSkzA
- https://www.jianshu.com/p/2547b0a15707