跨域实现详解

xiaoxiao2021-02-28  67

一直觉得jsonp很好用,却不知道原理,跨越技术有点多,在这探索解释一番,望有所获


同源策略

在JavaScript中,有一个很重要的安全性限制,被称为“Same-Origin Policy”(同源策略)。这一策略对于JavaScript代码能够访问的页面内容做了很重要的限制,即JavaScript只能访问与包含它的文档在同一域下的内容。(图片来自MDN)


JSONP

在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上用<script>标签引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。

jsonp的客户端实现 tocat服务器上有个remote.js(这里用tocat,web项目演示) alert("跨域成功");

本地index.html文件

<!DOCTYPE> <html> <head> <title>跨域资源</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> /* 完成跨域 */ <script src="http://localhost:8080/web/js/remote.js"></script> </head> <body> </body> </html>

很明显,显示跨域成功

接下来我们在本地index.html定义callback函数 ,然后远程tomcat.js传入回调数据, index.html <!DOCTYPE> <html> <head> <title>跨域资源</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> /* 完成跨域 */ <script type="text/javascript"> window.onload = function() { var callback = function(data) { alert("跨域调用远程tomcat.js成功: " + data.name); } } </script> <script src="http://localhost:8080/web/js/tomcat.js"></script> </head> <body> </body> </html>

远程服务器: tomcat.js

callback({"name":"kk"});

到此,跨域基本实现,但是这里有个问题,远程站点怎么知道要调用哪个callback呢? 所以就有了jsonp的核心:服务端提供的callback是动态生成的, 本地只要动态传一个callback给服务端,服务端就知道该调用哪个了 像这样: 客户端

<!DOCTYPE> <html> <head> <title>跨域资源</title> <meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> <script type="text/javascript"> window.onload = function() { var callback = function(data) { alert("跨域调用远程成功: " + data.name); } var url = "http://localhost:8080/web/js/helloServlet?userid=1&callback=callback"; // 创建script标签,设置其属性 var script = document.createElement('script'); script.setAttribute('src', url); // 把script标签加入head,此时调用开始 document.getElementsByTagName('head')[0].appendChild(script); } </script> </head> <body> </body> </html>

服务端:(这里选用java解释)

// 从客户端获取参数userid和callback PrintWriter out =response.getWriter(); // 根据userid查找到的数据存储为json, out.println(callback+"("+json+")"); // 返回给客户端的代码,callback(json)

jsonp的执行全过程就是这么回事了(个人理解)

现在再来看JQuery中的实现,我们最经常用的$.ajax,似乎通透了不少,也就是这么回事 $(function() { $.ajax({ async: false, url: http, //跨域url地址 type: "GET", dataType: 'jsonp', jsonp: 'jsoncallback', data: { "userid": "1" }, timeout: 5000, beforeSend: function() { //jsonp 方式此方法不被触发.原因可能是dataType如果指定为jsonp的话,就已经不是ajax事件了 }, success: function(json) { //客户端jquery预先定义好的callback函数,成功获取跨域服务器上的json数据后,会动态执行这个callback函数 } error: function(xhr) { //jsonp 方式此方法不被触发.原因是:dataType如果指定为jsonp的话,就已经不是ajax事件了 //请求出错处理 alert("请求出错(请检查相关度网络状况.)"); } }); })

这里发现,$.ajax和ajax并不是一回事啊,ajax的核心是通过XmlHttpRequest获取非本页内容,而jsonp的核心则是动态添加


window.name

注意,window.name的值只能是字符串的形式,这个字符串的大小最大能允许2M左右甚至更大的一个容量,具体取决于不同的浏览器,但一般是够用了。 实例: 假设有三个页面:

http://a.com/a.html //渴望获得数据的页面 http://a.com/b.html //a的兄弟页面,充当中间人角色 http://b.com/data.html //不同源的数据页 http://a.com/a.html,监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理页面http://a.com/b.html(代理文件和应用页面在同一域下,所以可以相互通信) 动态创建iframe <script type="text/javascript"> var state = 0, iframe = document.createElement('iframe'); // 通过iframe的src与data.html通信 iframe.src = 'http://b.com/data.html'; //监听onload if (iframe.attachEvent) { iframe.attachEvent('onload', loadfn); } else { iframe.onload = loadfn; var loadfn = function() { if (state === 0) { state = 1; iframe.contentWindow.location = "http://a.com/b.html"; // 设置的代理页面 } else if (state === 1) { var data = iframe.contentWindow.name; // 读取数据 alert(data); //弹出'data.html!' } }; </script> http://b.com/data.html <script type="text/javascript"> window.name = 'data.html'; </script>

这样就可以成功解决了,理一下思路,应该是这样: 充当中间人的iframe想要获取到data.html的通过window.name设置的数据,只需要把这个iframe的src设为www.cnblogs.com/data.html就行了。然后a.html想要得到iframe所获取到的数据,也就是想要得到iframe的window.name的值,还必须把这个iframe的src设成跟a.html页面同一个域才行 图示:


HTML5中新引进的window.postMessage方法

在HTML5中新增了postMessage方法,postMessage可以实现跨文档消息传输(Cross Document Messaging),Internet Explorer 8, Firefox 3, Opera 9, Chrome 3和 Safari 4都支持postMessage。

实现: 发送信息的页面http://a.com/a.html

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>客户端</title> <script type="text/javascript"> window.onload = function() { window.frames[0].postMessage('data', 'http://b.com/data.html'); //postMessage接收两个参数,第一个数据,第二个字符串参数,指明目标窗口的源,具体看MDN } </script> </head> <body> <iframe id="child" src="http://b.com/data.html"></iframe> </body> </html>

接收信息的页面http://b.com/data.html

// 通过监听message事件获取数据 window.addEventListener('message',function(e){ var e =e||event; alert(e.data); },false);

图示:


跨域资源共享(CORS)

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。 它允许浏览器向跨源服务器,发出XMLHttpRequest请求,从而克服了AJAX只能同源使用的限制。

整个CORS通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS通信与同源的AJAX通信没有差别,代码完全一样。浏览器一旦发现AJAX请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

**因此,实现CORS通信的关键是服务器。只要服务器实现了CORS接口,就可以跨源通信。**具体原理参见MDN

当然:还有document.domain…以上十个人理解,ps: 欢迎指正
转载请注明原文地址: https://www.6miu.com/read-65022.html

最新回复(0)