跨域问题
# 跨域问题
原因:浏览器的同源策略。从安全性的角度考虑,为了限制非同源的接口请求和DOM查询。
同源:协议、IP地址、端口号相同的属于同源。
PS:域名和域名对应的IP地址,也属于跨域。
# JSONP
原理:script标签的获取是不受跨域限制的,因此可以通过加载跨域的js来实现跨域。
限制:只能进行get请求。
实现方法:
<script>
function fn(data){
// 对于请求的数据的操作
console.log(data);
}
</script>
<script src="http://domain.com/api?callback=fn"></script>
2
3
4
5
6
7
# CORS
CORS
是一个W3C的标准,全称是跨域资源共享,允许浏览器向跨域服务器发送网络请求。
CORS标准将请求分为两类,简单请求和非简单请求。
CORS请求的响应头,都以Access-Control-
开头:
Access-Control-Allow-Origin
:必选。允许跨域请求的源,要么为请求头中Origin
的值,要么为*Access-Control-Allow-Credentials
:可选。表示是否允许发送cookieAccess-Control-Expose-Headers
:可选。允许额外暴露的响应头字段(默认情况下只允许使用Cache-Control
、Content-Language
、Content-Type
、Expires
、Last-Modified
、Pragma
六个字段)
# 简单请求
简单请求的定义是:
- 请求方法是GET、POST、HEAD中的一种
- header中的字段不超过:
Accept
、Accept-Language
、Content-Language
、Content-Type
对于简单请求,浏览器直接发送CORS请求。并在请求头中添加一个Origin
字段,服务器根据这个字段决定是否同意这次请求。
# 非简单请求
对于非简单请求,会在通信前增加一次查询,称为“预检请求”。
预检请求使用的方法是OPTION
,并附加三个字段:
Origin
:发送请求的源Access-Control-Request-Method
:必选。列出浏览器要用到哪些请求方法Access-Control-Request-Headers
:可选。列出浏览器要使用的额外的请求头字段
服务器收到预检请求后,根据上述三个字段的值判断是否允许。若确认允许,则返回响应。对于非简单请求特有的是:
Access-Control-Allow-Methods
:必选。列出允许使用的所有方法,而不只是请求中列出的方法(避免多次预检请求)Access-Control-Allow-Headers
:若请求中包含Access-Control-Request-Headers
则必选。列出支持的所有头部字段Access-Control-Max-Age
:可选。本次预检请求的有效时间
# nginx代理
有两种思路:
- 和CORS一样,通过设置
Access-Control-
系列字段实现跨域。 - 通过反向代理。由于服务端的请求不存在跨域问题,以nginx为中转可以将一个跨域的服务代理到同源上
# 中间件跨域
和nginx原理相同,通过代理服务器实现数据转发。
# WebSocket
WebSocket是一种HTML5的新协议,用于实现浏览器和服务器的全双工通信,并且支持跨域
# document.domain + iframe
仅限两个页面的主域相同,子域不同的情况。 eg:http://www.domain.com/a.html和http://child.domain.com/b.html。
原理:两个页面都通过js强制设置document.domain为基础主域(相同的domain.com)
# location.hash + iframe
A域的a页面和B域的b页面之间想要通信,则通过一个A域的c页面。
a和b、b和c之间,都是单向通信,但a和c之间是同域所以可以实现双向通信
# window.name + iframe
window.name
属性的特殊之处:在不同的页面加载后仍然存在,且可以支持很长的name值(2MB)
原理:
- a.html要和b.html通信,引入一个代理页面proxy.html。
- 在a中,先用iframe加载b,然后再次加载proxy,此时window.name属性仍然存在,且a和proxy同域可以读取
# postMessage
postMessage
是HTML5新提供的允许跨域的API,可以实现页面和iframe之间的消息传递