前端跨域
2017-08-02 16:32 库奇—— 阅读(226) 评论(0) 编辑 收藏 举报同源策略
同源策略是由Netscape提出来的一种广泛应用至今的安全策略,它规定必须符合域名、端口、协议完全相同的页面之间才能够互相访问对方的数据,包括BOM、后端接口等,所有支持JavaScript的浏览器都遵守同源策略,这也是出现跨域问题的原因。
一:利用 JSONP 实现跨域调用
实现原理: <script>元素的src 属性还可以包含来自外部域的JavaScript 文件。
JSONP 是 JSON 的一种使用模式,可以解决主流浏览器的跨域数据访问问题。其原理是根据 XmlHttpRequest 对象受到同源策略的影响,而 <script> 标签元素却不受同源策略影响,可以加载跨域服务器上的脚本,网页可以从其他来源动态产生 JSON 资料。用 JSONP 获取的不是 JSON 数据,而是可以直接运行的 JavaScript 语句。
JSONP协议建立在网页允许跨域加载JavaScript脚本文件的前提下,具体步骤是:
- 请求发起方在页面添加一个script标签,地址是另一个域的接口地址
- 请求发起方通过接口地址的URL查询字符串传递参数,包括约定好的回调函数名称(比如callback)
- 响应方收到请求并且处理数据,生成一段调用回调函数的JavaScript代码并返回
- script标签加载到JavaScript代码后自动执行回调函数,将返回的数据传递给回调函数作为参数
比如:
http://www.domain.com/a.html页面添加一个标签
<script src=“http://test.domain.com/b.php?callback=fun1&id=1”></script>
http://test.domain.com/b.php接收请求并生成JavaScript代码返回。
fun(
{code: 0,data: 1234}
);
下面是一个简单的请求百度接口的jsonp
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>jsonp</title> </head> <body> <div style="text-align: center;"> <input type="text" id="text" > </div> <ul id="listBox"> </ul> <script> /* JSONP协议建立在网页允许跨域加载JavaScript脚本文件的前提下,具体步骤是: 请求发起方在页面添加一个script标签,地址是另一个域的接口地址 请求发起方通过接口地址的URL查询字符串传递参数,包括约定好的回调函数名称(比如callback) 响应方收到请求并且处理数据,生成一段调用回调函数的JavaScript代码并返回 script标签加载到JavaScript代码后自动执行回调函数,将返回的数据传递给回调函数作为参数*/ text.oninput=function(ev){ if(!scrEle){ var scrEle = document.createElement("script"); scrEle.id = "scrEle"; scrEle.src = "https://sp0.baidu.com/5a1Fazu8AA54nxGko9WTAnF6hhy/su?cb=callback&wd="+ev.target.value//wd为查询参数 cb为回掉函数 document.getElementsByTagName("head")[0].appendChild(scrEle); }else{ document.body.removeChild(scrEle); } } function callback(json) { listBox.innerHTML = ''; for(var i = 0; i < json.s.length; i ++) { listBox.innerHTML += '<li>'+json.s[i]+'</li>' } } </script> </body> </html>
优点:1使用简单 2 兼容性好 3
缺点:1它只支持GET请求而不支持POST等其它类型的HTTP请求 2 jsonp在调用失败的时候不会返回各种HTTP状态码。 3 安全性
二 :使用 CORS 实现跨域调用
CORS(Cross-Origin Resource Sharing,跨源资源共享)是W3C 的一个工作草案,定义了在必须访问跨源资源时,浏览器与服务器应该如何沟通。CORS 背后的基本思想,就是使用自定义的HTTP 头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。
对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。
因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。
服务器端对于CORS的支持,主要就是通过设置Access-Control-Allow-Origin来进行的。
优点:
- JSONP只能实现GET请求,而CORS支持所有类型的HTTP请求。
- 使用CORS,开发者可以使用普通的XMLHttpRequest发起请求和获得数据,比起JSONP有更好的错误处理。
缺点:
- 需要服务器的支持
- JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS)。
三:图像Ping
我们知道,一个网页可以从任何网页中加载图像,不用担心跨域不跨域。这也是在线广告跟踪浏览量的主要方式。也可以动态地创图像,使用它们的onload 和onerror 事件处理程序来确定是否接收到了响应。
动态创建图像经常用于图像Ping。图像Ping 是与服务器进行简单、单向的跨域通信的一种方式。请求的数据是通过查询字符串形式发送的,而响应可以是任意内容,但通常是像素图或204 响应。通过图像Ping,浏览器得不到任何具体的数据,但通过侦听load 和error 事件,它能知道响应是什么时候接收到的。
来看下面的例子。
var img = new Image();
img.onload = img.onerror = function(){
alert("Done!");
};
img.src = "http://www.example.com/test?name=Nicholas";这里创建了一个Image 的实例,然后将onload 和onerror 事件处理程序指定为同一个函数。这样无论是什么响应,只要请求完成,就能得到通知。请求从设置src 属性那一刻开始,而这个例子在请求中发送了一个name 参数。图像Ping 最常用于跟踪用户点击页面或动态广告曝光次数。
图像Ping 有两个主要的缺点,
- 一是只能发送GET 请求,
- 二是无法访问服务器的响应文本。
因此,图像Ping 只能用于浏览器与服务器间的单向通信。.
四:使用web socket
使用web sockets是一种浏览器的API,它的目标是在一个单独的持久连接上提供全双工、双向通信。(同源策略对web sockets不适用)
web sockets原理:在JS创建了web socket之后,会有一个HTTP请求发送到浏览器以发起连接。取得服务器响应后,建立的连接会使用HTTP升级从HTTP协议交换为web sockt协议。
只有在支持web socket协议的服务器上才能正常工作。
var socket = new WebSockt('ws://www.baidu.com');//http->ws; https->wss
socket.send('hello WebSockt');
socket.onmessage = function(event){
var data = event.data;
}
五:跨域页面数据通讯
1:不同主域的页面
HTML5提供了postMessage/sendMessage等API允许从一个域发送消息到指定的域,另一个域下的网页可以通过onmessage监听消息并且做出处理。跨文档消息传送,有时候简称为XDM,指的是在来自不同域的页面间传递消息。
postMessage(data,origin)方法接受两个参数
1.data:要传递的数据,html5规范中提到该参数可以是JavaScript的任意基本类型或可复制的对象,然而并不是所有浏览器都做到了这点儿,部分浏览器只能处理字符串参数,所以我们在传递参数的时候需要使用JSON.stringify()方法对对象参数序列化,在低版本IE中引用json2.js可以实现类似效果。
2.origin:字符串参数,指明目标窗口的源,协议+主机+端口号[+URL],URL会被忽略,所以可以不写,这个参数是为了安全考虑,postMessage()方法只会将message传递给指定窗口,当然如果愿意也可以建参数设置为"*",这样可以传递给任意窗口,如果要指定和当前窗口同源的话设置为"/"。
1:http://wowo.yinker.com
var iframe = document.getElementById('iframe'); iframe.onload = function() { var data = { name: 'aym' }; // 向domain2传送跨域数据 iframe.contentWindow.postMessage(JSON.stringify(data), 'http://xc.yinker.com/page/aboutUs.do'); }; // 接受domain2返回数据 w window.addEventListener('message', function(e) { console.log(e.data); }, false);
2:http://xc.yinker.com
window.addEventListener('message', function(event){
console.log(event.origin)
if (event.origin == 'http://wowo.yinker.com') {
console.log(event.data); //name: 'aym'
window.parent.postMessage("另一个域名发送过来的", 'http://wowo.yinker.com');
}
}, false)
2: 同主域嵌套页面 document.domain + iframe跨域
修改domain为主域,比如a.domain.com修改为domain.com,即可互相访问浏览器对象模型。
1.)父窗口:http://wowo.yinker.com/page/aboutUs.do
<iframe id="iframe" src="http://xc.yinker.com/page/aboutUs.do"></iframe> <script> document.domain = 'yinker.com'; var user = 'admin'; console.log(document.getElementById('iframe').contentWindow.child)//获取子ifarme的变量 </script>
2.)子窗口:http://xc.yinker.com/page/aboutUs.do
3:不同主域嵌套页面
修改子页面的iframe的hash值