对Javascript跨域问题的深入分析
什么是跨域?
假设a.com/get.html需要在b.com/data.html,获取数据,而a.com和b.com在这里不是同一个服务器,也就是跨域和跨域会涉及到Javascript的同源策略。简单来说就是保护网站的安全,不被外来(非同源)服务器的js修改。引用一个表格,看看是什么条件导致了交叉因素:
但是有时候我们真的需要这样做,那么我们有什么方法呢?
1、JsonP
提到jsonp就不能不提跨域。实际上,jsonp是带有填充的Java脚本对象表示法的简称,可以理解为用内容填充的json格式数据。因为上面声明了回调并调用了外域b.com的data.js,而data.js调用了回调({ msg : ' tqttan ' });这样在调用引用外域的js时,就会调用局部回调()来实现数据传输。以上只是简单的跨域。让我们看看jQuery的真实应用。
jQuery中的Ajax可以通过两种方式拉取外域的数据:
1、$.getJSON()
这种方法简单粗暴,并且请求域外的Json。
复制代码如下:美元。getjson(' http://b.com/dataservlet?回调=?”,函数(数据){ console . log(data . msg);});
假设上面的请求访问b.com下的servlet页面,传递的参数是callback=?jQuery会自动生成字符串来填充占位符吗?例如,回调=jquery17207481773362960666 _ 1332575486681。这就用服务器声明了唯一的标签,服务器只需要用这个回调值返回json格式的数据,例如:
复制代码如下://dataservlet.javastring回调=req.getparameter('回调');PrintWriter out=resp . getwriter();out.print(回调'(' msg ',' tqtan '));
这样就可以成功获取非同源服务器的数据。
2、$.ajax()
实现原理同上,只是可以定制更多的链接。
$.Ajax({ URL : ' http://b.com/DataServlet?words=hi ',dataType:'jsonp ',jsonp : 'jsoncallback ',jsoncallback : 'tqtan ',success : function(data){ console . log(data . msg);},error:函数(e){ console . log(e);}});您可以自定义回调的名称,并在此将其更改为“tqtan”。同时,可以在这里传递value words=hi。请注意,JsonP格式只能以GET的形式请求服务器。
2、文档.域
该方法仅适用于主域相同但子域不同的跨域。也就是get.a.com和data.a.com之间的跨域问题,解决方法很简单:如果get.a.com/get.html需要从data.a.com/data.html,获取数据,先在get.html插入一个iframe,src指向data.a.com/data.html,然后在data.html写document . domain=' a.com ';你可以在data.html操纵内容。
//get . html var iframe=document . create element(' iframe ');iframe . src=' http :http://data . a.com/data . html ';iframe . style . display=' none ';document . body . appendchild(iframe);document . domain=' a.com ';iframe . onload=function(){ var other document=iframe . content document | | iframe . content window . document;//otherDocument是另一页的文档//想做什么就做什么.};//data . html document . domain=' a.com ';3、url哈希
你也可以使用网址的散列来实现跨域。哈希是url#后面的内容,例如http://targetkiller.net/index.html#data,其中#数据是哈希。如何利用这一点实现跨域?
又如,a.com/get.html需要获得b.com/data.html. First,在get.html建立一个iframe,src仍然指向data.html,后面跟哈希值实现参数传输。在另一端,data.html根据获得的散列进行响应,并自己创建一个iframe。src指向a.com/proxy.html并将响应数据添加到哈希中。之后,a.com/proxy.html只需要修改get.html在同一个a.com父域中的哈希。最后,如何获取数据?只需在get.html写一个定时器设置间隔,并定期收听新的散列。
看到这里,你可能会感到困惑,几个问题:
1.proxy.html的作用?由于get.html和data.html不在一个域上,所以不能修改位置。哈希值,于是运用proxy.html,先跳到找个代理页面,然后通过parent.location.hash,也就是修改父亲,让儿子(get.html)也得到响应。a.com/get.html
var iframe=document。创建元素(“iframe”);iframe。src='http://a.com/get.html#data';iframe。风格。显示='无';文件。尸体。append child(iframe);//周期检测混杂更新函数getHash(){ var data=location。哈希?位置。哈希。子字符串(1): " ";console.log(数据);} var hashInt=setInterval(function(){ getHash()},1000);a.com/proxy.htmlparent.location.hash=自我。位置。哈希。子串(1);b.com/data.html//模拟一个简单的参数处理操作if(位置。hash){ var data=location。哈希;doSth(数据);}函数doSth(数据){console.log('来自a.com: '数据);var msg='你好我是' b.com ';var iframe=document。创建元素(“iframe”);iframe。src=' http://a.com/proxy。html # ' msgiframe。风格。显示='无';文件。尸体。append child(iframe);}4、窗口。名称
这种方法比较巧妙,引用圆心的解释,名称值在不同的页面(甚至不同域名)加载后依旧存在,并且可以支持非常长的名字值(2MB)。具体例子依旧如上,同时也是需要一个代理页面。a.com/get.html请求b.com/data.html,首先get.html创建一个iframe,src指向data.html,然后监听内联框架的装载事件。与此同时,在data.html设置window.name=数据把窗口。名称赋值。然后装载事件后马上把内联框架的跳到本地a.com/proxy.html。因此窗口。名称就共享到了科学研究委员会为proxy.html的找个内联框架中,接下来,就是同源间获取值的事了。a.com/get.html
var状态=0,iframe=document。createelement(' iframe '),iframe。src='http://b.com/data.html';iframe。风格。显示='无';load fn=function(){ if(state===1){ var data=iframe。内容窗口。姓名;console.log(数据);} else if(state===0){ state=1;//跳到代理人。html iframe。contentwindow。位置='http://a.com/proxy.html';}};if(iframe。attachevent){ iframe。attachevent(' on load ',load fn);} else { iframe.onload=loadfn}文档。尸体。append child(iframe);a.com/proxy.html//proxy.html的操作主要是删除get.html的iframe,避免安全问题发生iframe。内容窗口。文件。write(');iframe。内容窗口。close();文件。尸体。移除子对象(iframe);b.com/data.htmlvar数据='你好,tqtan ';window.name=data5,后期消息()
html5的新方法postMessage()优雅地解决了跨域,也十分容易理解。发送方调用postMessage()内容,接受方监听onmessage接受内容即可。假设发送方为a.com/send.html,接受方为b.com/receive.html。a.com/send.html
var iframe=document。创建元素(“iframe”);iframe。src='http://b.com/receive.html';文件。尸体。append child(iframe);iframe。内容窗口。postmessage(' hello ',' http://b.com ');接收。html窗口。addeventlistener(' message ',function(event){//通过起源属性判断消息来源地址if(事件。origin==' http://a.com '){ console。日志(事件。数据);控制台。日志(事件。来源);//发送源的窗户值}},false);6、CORS(后台实现)
以上5点都是前端实现的跨域,但是后台参与会让跨域更容易解决,也就是用CORS。克-奥二氏分级量表是跨来源资源共享的简称,也就是跨域资源共享。它有多牛逼?之前说JsonP只能得到请求,但克-奥二氏分级量表则可以接受所有类型的超文本传送协议(超文本传输协议的缩写)请求,然而克-奥二氏分级量表只有现代浏览器才支持。怎样使用?前端只需要发普通创建交互式、快速动态网页应用的网页开发技术请求,注意检测克-奥二氏分级量表的支持度。引用自蒋宇捷。
函数createCORSRequest(方法,URL){ var xhr=new XMLHttpRequest();if(' xhr中的带有凭据'){//此时即支持克-奥二氏分级量表的情况//检查XMLHttpRequest对象是否有"带密码"属性//"带字符"仅存在于XMLHTTPRequest2对象里xhr.open(方法、url、true);}else if (typeof!='undefined') {//否则检查是否支持XDomainRequest,IE8和IE9支持//XDomainRequest仅存在于工业管理学(工业工程)中,是工业管理学(工业工程)用于支持克-奥二氏分级量表请求的方式xhr=new XDomainRequest();xhr.open(方法,网址);} else {//否则,浏览器不支持CORSxhr=null}返回xhr } var xhr=createCORSRequest(' GET ',URL);if(!xhr){ 0抛出新错误('不支持CORS ');}与此同时,服务器端只需要设置访问控制允许来源头即可。
爪哇岛中你只需要设置
复制代码代码如下:response.setHeader('访问控制-允许-源',' * ');
为了安全,也可以将*改为特定域名,例如a.com。
版权声明:对Javascript跨域问题的深入分析是由宝哥软件园云端程序自动收集整理而来。如果本文侵犯了你的权益,请联系本站底部QQ或者邮箱删除。