跨域方式总结

因为浏览器处于安全考虑,有同源策略。换句话说,如果协议、域名或者端口有一个不同的话就是跨域。由于Ajax只能获取同源的资源,因此Ajax请求会失败。

下面我们就来总结一下跨域方式有哪一些:

1. 方法一:JSONP

原理:Web页面上调用js文件不受跨域影响,凡是具有src属性标签都不受同源策略的影响,正是因为这个特性,我们把资源放到script标签中,src属性的格式是”url+参数”,比如url?cd=doJSON,cd是我们和后台协商好的类似于形参的东西,是一个留给我们写处理函数接口,doJSON就是我们事先定义好的函数,也就是回调函数,所有数据会以参数的形式传递给该函数(json是一种数据格式,jsonp是一种约定俗成的非正式传输协议)。
注意:JSONP使用简单且兼容老版本浏览器,但是只限于get请求。
为什么不支持post请求?因为jsonp的方式原理上和``是一致的,因为它原理实际上就是使用js的script标签进行传参,那么必然是get方式了,和浏览器中敲入一个url是一样的。

2. 方法二:CORS跨域资源共享

原理:需要浏览器和后端同时支持。要在服务器端的response header里面加一个Access-Control-Allow-Origin:指定域名||* (表示所有域名都可以跨域),浏览器端便可以发起post的跨域请求。浏览器会自动进行CORS通信,实现CORS通信的关键是后端。只要后端实现了CORS,就实现了跨域。
IE8和IE9需要通过XDomainRequest来实现。它实现了CORS的部分规范,只支持GET/POST形式的请求。在服务器端,依旧要求在响应报头添加”Access-Control-Allow-Methods”标签(这点跟CORS一致)。创建一个XDomainRequest的实例,调用open()方法,再调用send()方法,请求返回之后,会触发load事件,相应的数据也会保存在responseText属性中。

3. 方法三:Document.domain

前提条件:这两个域名必须属于同一个基础域名,而且所有的协议、端口都要一致,否则无法利用document.domain进行跨域。
比如:a.test.com和b.test.com(它们服务器域名不同,但是拥有相同的上级域名test.com)适用于该方法。只需要给页面添加document.domain=’test.com’表示二级域名都相同就可以实现跨域了。
document.domain是用来得到当前网页的域名,可以赋成当前域名或者基础域名

  1. 当前域名
    如:aaa.com有一个网页(a.html),利用iframe引入了一个bbb.com里面的网页(b.html)。这时在a.html里面可以看到b.html里面的内容,但是却不能用js来操作它,因为这两个页面属于不同的域。但是如果在a.html里面引入aaa.com里面的另一个网页,就不会有这个问题了,因为它们的域是相等的。
  2. 基础域名
    两个子域名:aaa.xxx.com和bbb.xxx.com,aaa里面的一个网页(a.html)引入了bbb里面的一个网页(b.html),这时a.html里同样是不能操作b.html里面的内容。因为document.domain不一样,一个是aaa.xxx.com,另一个是bbb.xxx.com。这时我们就可以通过js,将两个页面的domain改成一样的,需要在a.html里与b.html里都加入:document.domain="xxx.com"

需要注意:一个网页被攻击,另外一个站点就会引起安全漏洞。

4. 方法四:postMessage

h5中有一个功能就是跨文档消息传输。
getMessageHTML.postMEssage(message,targetOrigin);
getMessageHTML是接受信息的页面引用,可以是iframe的contentWindow,window.open的返回值;
targetOrigin是用于限制getMessageHTML的,填* 的时候不做限制。

5. 方法五:服务器代理

服务器不受同源策略的影响,把所有资源放在服务器上,然后让服务器上的网页获取这些资源。

1
2
3
4
5
6
7
8
9
10
11
// 发送消息端
window.parent.postMessage('message','http://test.com');

// 接收消息端
var mc = new MessageChannel(); // 允许我们创建一个新的消息通道
mc.addEventListener('message',(event)=>{
var origin = event.origin || event.originalEvent.origin;
if(origin === 'http://test.com'){
console.log('验证通过');
}
});

方法六:Iframe

  1. iframe+location.hash
    利用location.hash来传值,改变hash不会刷新页面;

缺点:数据直接暴露在url中,并且数据长度和类型都有限制。

  1. iframe+window.name
    和location.hash方法差不多,主页面有一个iframe,通过修改引入的子页面(同源的)来获取window.name值来达到跨域。

缺点:需要借助同源其他子页面。