JavaScript跨域解决方案.docx
- 文档编号:11679818
- 上传时间:2023-03-30
- 格式:DOCX
- 页数:6
- 大小:23.15KB
JavaScript跨域解决方案.docx
《JavaScript跨域解决方案.docx》由会员分享,可在线阅读,更多相关《JavaScript跨域解决方案.docx(6页珍藏版)》请在冰豆网上搜索。
JavaScript跨域解决方案
Javascript跨域访问解决方案之马矢奏春创作
创作时间:
二零二一年六月三十日
在客户端编程语言中,如javascript和ActionScript,同源战略是一个很重要的平安理念,它在保证数据的平安性方面有着重要的意义.同源战略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和把持另外一个域的绝年夜部份属性和方法.那么什么叫相同域,什么叫分歧的域呢?
同源战略
在客户端编程语言中,如javascript和ActionScript,同源战略是一个很重要的平安理念,它在保证数据的平安性方面有着重要的意义.同源战略规定跨域之间的脚本是隔离的,一个域的脚本不能访问和把持另外一个域的绝年夜部份属性和方法.那么什么叫相同域,什么叫分歧的域呢?
当两个域具有相同的协议(如http),相同的端口(如80),相同的host(如),那么我们就可以认为它们是相同的域.比如和是同域,而,,,中的任何两个都将构成跨域.同源战略还应该对一些特殊情况做处置,比如限制file协议下脚本的访问权限.本地的HTML文件在浏览器中是通过file协议翻开的,如果脚天性通过file协议访问到硬盘上其它任意文件,就会呈现平安隐患,目前IE8还有这样的隐患.
受到同源战略的影响,跨域资源共享就会受到制约.可是随着人们的实践和浏览器的进步,目前在跨域请求的技巧上,有很多贵重经验的沉淀和积累.这里我把跨域资源共享分成两种,一种是单向的数据请求,还有一种是双向的消息通信.接下来我将罗列出罕见的一些跨域方式,以下跨域实例的源代码可以从这里获得.
什么是跨域
JavaScript出于平安方面的考虑,不允许跨域调用其他页面的对象.但在平安限制的同时也给注入iframe或是ajax应用上带来了很多麻烦.这里把涉及到跨域的一些问题简单地整理一下:
首先什么是跨域,简单地舆解就是因为JavaScript同源战略的限制,域名下的js无法把持或是域名下的对象.更详细的说明可以看下表:
URL
说明
是否允许通信
同一域名下
允许
同一域名下分歧文件夹
允许
同一域名,分歧端口
不允许
同一域名,分歧协议
不允许
域名和域名对应ip
不允许
主域相同,子域分歧
不允许
同一域名,分歧二级域名(同上)
不允许(cookie这种情况下也不允许访问)
分歧域名
不允许
特别注意两点:
第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
第二:
在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去检验考试判断相同的ip地址对应着两个域或两个域是否在同一个ip上.“URL的首部”指window.location.protocol+window.location.host,也可以理解为“Domains,protocolsandportsmustmatch”.
接下来简单地总结一下在“前台”一般处置跨域的法子,后台proxy这种方案牵涉到后台配置,这里就不管述了,有兴趣的可以看看yahoo的这篇文章:
《JavaScript:
UseaWebProxyforCross-DomainXMLHttpRequestCalls》
1、document.domain+iframe的设置
对主域相同而子域分歧的例子,可以通过设置document.domain的法子来解决.具体的做法是可以在=‘’;然后通过a.html文件中创立一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了.固然这种法子只能解决主域相同而二级域名分歧的情况,如果你异想天开的把的domian设为那显然是会报错地!
代码如下:
document.domain='';varifr=document.createElement('iframe');ifr.src='='none';document.body.appendChild(ifr);ifr.onload=function(){vardoc=ifr.contentDocument||ifr.contentWindow.document;//在这里把持b.htmlalert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);};
document.domain='';
这种方式适用于{,,,}中的任何页面相互通信.
备注:
某一页面的domain默认即是window.location.hostname.主域名是不带www的域名,例如,主域名前面带前缀的通常都为二级域名或多级域名,例如其实是二级域名.domain只能设置为主域名,不成以在中将domain设置为.
问题:
1、平安性,当一个站点()被攻击后,另一个站点()会引起平安漏洞.
2、如果一个页面中引入多个iframe,要想能够把持所有iframe,必需都得设置相同domain.
2、静态创立script
虽然浏览器默认禁止了跨域访问,但其实不由止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括把持cookie、Dom等等).根据这一点,可以方便地通过创立script节点的方法来实现完全跨域的通信.具体的做法可以参考YUI的GetUtility
这里判断script节点加载完毕还是蛮有意思的:
ie只能通过script的readystatechange属性,其它浏览器是script的load事件.以下是部份判断script加载完毕的方法.
js.onload=js.onreadystatechange=function(){if(!
this.readyState||this.readyState==='loaded'||this.readyState==='complete'){//callback在此处执行js.onload=js.onreadystatechange=null;}};
分歧的域之间,JavaScript只能做很有限的访问和把持,其实我们利用这些有限的访问权限就可以到达跨域通信的目的了.FIM(FragmentIdentitierMessaging)就是在这个年夜前提下被发明的.父窗口可以对iframe进行URL读写,iframe也可以读写父窗口的URL,URL有一部份被称为frag,就是#号及其后面的字符,它一般用于浏览器锚点定位,Server端其实不关心这部份,应该说HTTP请求过程中不会携带frag,所以这部份的修改不会发生HTTP请求,可是会发生浏览器历史记录.FIM的原理就是改变URL的frag部份来进行双向通信.每个window通过改变其他window的location来发送消息,并通过监听自己的URL的变动来接收消息.这个方式的通信会造成一些不需要的浏览器历史记录,而且有些浏览器不支持onhashchange事件,需要轮询来获知URL的改变,最后,URL在浏览器下有长度限制,这个制约了每次传送的数据量.
这个法子比力绕,可是可以解决完全跨域情况下的脚步置换问题.原理是利用location.hash来进行传值.在url:
#helloword中的‘#helloworld’就是location.hash,改变hash其实不会招致页面刷新,所以可以利用hash值来进行数据传递,固然数据容量是有限的.假设域名下的文件cs1.html要和域名下的cs2.html传递信息,cs1.html首先创立自动创立一个隐藏的iframe,iframe的src指向域名下的cs2.html页面,这时的hash值可以做参数传递用.cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于域名下的一个代办署理iframe;Firefox可以修改).同时在cs1.html上加一个按时器,隔一段时间来判断location.hash的值有没有变动,一点有变动则获取获取hash值.
代码如下:
先是下的文件cs1.html文件:
functionstartRequest(){varifr=document.createElement('iframe');ifr.style.display='none';ifr.src='document.body.appendChild(ifr);}functioncheckHash(){try{vardata=location.hash?
location.hash.substring
(1):
'';if(console.log){console.log('Nowthedatais'+data);}}catch(e){};}setInterval(checkHash,2000);
域名下的cs2.html:
//模拟一个简单的参数处置把持switch(location.hash){case'#paramdo':
callBack();break;case'#paramset':
//dosomething……break;}functioncallBack(){try{parent.location.hash='somedata';}catch(e){//ie、chrome的平安机制无法修改parent.location.hash,//所以要利用一个中间的cnblogs域下的代办署理iframevarifrproxy=document.createElement('iframe');ifrproxy.style.display='none';ifrproxy.src='//注意该文件在""域下document.body.appendChild(ifrproxy);}}
//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值parent.parent.location.hash=self.location.hash.substring
(1);
固然这样做也存在很多缺点,诸如数据直接流露在了url中,数据容量和类型都有限等……
AccessControl是比力超越的跨域方式,目前只在很少的浏览器中得以支持,这些浏览器可以发送一个跨域的HTTP请求(Firefox,谷歌Chrome等通过XMLHTTPRequest实现,IE8下通过XDomainRequest实现),请求的响应必需包括一个Access-Control-Allow-Origin的HTTP响应头,该响应头声明了请求域的可访问权限.例如对下的asset.php发送了一个跨域的HTTP请求,那么asset.php必需加入如下的响应头:
window对象的name属性是一个很特另外属性,当该window的location变动,然后重新加载,它的name属性可以依然坚持不变.那么我们可以在页面A中用iframe加载其他域的页面B,而页面B中用JavaScript把需要传递的数据赋值给window.name,iframe加载完成之后,页面A修改iframe的地址,将其酿成同域的一个地址,然后就可以读出window.name的值了.这个方式非常适合单向的数据请求,而且协议简单、平安.不会像JSONP那样不做限制地执行外部脚本.
文章较长列在此处方便于阅读,详细请看 .
5、使用HTML5postMessage
HTML5中最酷的新功能之一就是 跨文档消息传输CrossDocumentMessaging.下一代浏览器都将支持这个功能:
Chrome2.0+、InternetExplorer8.0+,Firefox3.0+,Opera9.6+,和Safari4.0+.Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递.
otherWindow.postMessage(message,targetOrigin);
otherWindow:
对接收信息页面的window的引用.可以是页面中iframe的contentWindow属性;的返回值;通过name或下标从取到的值.message:
所要发送的数据,string类型.targetOrigin:
用于限制otherWindow,“*”暗示不作限制
',targetOrigin);};
"alert(event.source);//对、index.html中window对象的引用//但由于同源战略,这里event.source不成以访问window对象}},false);
参考文章:
《精通HTML5编程》第五章——跨文档消息机制、
6、利用flash
flashURLLoader
flash有自己的一套平安战略,服务器可以通过crossdomain.xml文件来声明能被哪些域的SWF文件访问,SWF也可以通过API来确定自身能被哪些域的SWF加载.当跨域访问资源时,例如从域请求域上的数据,我们可以借助flash来发送HTTP请求.首先,修改域上的crossdomain.xml(一般寄存在根目录,如果没有需要手动创立),把加入到白名单.其次,通过FlashURLLoader发送HTTP请求,最后,通过FlashAPI把响应结果传递给JavaScript.FlashURLLoader是一种很普遍的跨域解决方案,不外需要支持iOS的话,这个方案就无能为力了.
FlashLocalConnection
页面上的双向通信也可以通过Flash来解决,FlashAPI中有LocalConnection这个类,该类允许两个SWF之间通过进程通信,这时SWF可以播放在自力的FlashPlayer或者AIR中,也可以嵌在HTML页面或者是PDF中.遵循这个通信原则,我们可以在分歧域的HTML页面各自嵌套一个SWF来到达相互传递数据的目的了.SWF通过LocalConnection交换数据是很快的,可是每次的数据量有40kb的年夜小限制.用这种方式来跨域通信过于复杂,而且需要了2个SWF文件,实用性不强.
7、JSONP
JSONP(JSONwithPadding)是一个简单高效的跨域方式,HTML中的script标签可以加载并执行其他域的javascript,于是我们可以通过script标识表记标帜来静态加载其他域的资源.例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行.JSONP在此基础上加入了回调函数,pageB加载完之后会执行pageA中界说的函数,所需要的数据会以参数的形式传递给该函数.JSONP易于实现,可是也会存在一些平安隐患,如果第三方的脚本随意地执行,那么它就可以窜改页面内容,截获敏感数据.可是在受信任的双方传递数据,JSONP是非常合适的选择.
8、serverproxy
在数据提供方没有提供对JSONP协议或者window.name协议的支持,也没有对其它域开放访问权限时,我们可以通过serverproxy的方式来抓取数据.例如当域下的页面需要请求下的资源文件asset.txt时,直接发送一个指向/asset.txt的Ajax请求肯定是会被浏览器阻止.这时,我们在下配一个代办署理,然后把Ajax请求绑定到这个代办署理路径下,例如/proxy/,然后这个代办署理发送HTTP请求访问下的asset.txt,跨域的HTTP请求是在服务器端进行的,客户端并没有发生跨域的Ajax请求.这个跨域方式不需要和目标资源签订协议,带有侵略性,另外需要注意的是实践中应该对这个代办署理实施一定水平的呵护,比如限制他人使用或者使用频率.
9、CrossFrame
CrossFrame是FIM的一个变种,它借助了一个空白的iframe,不会发生过剩的浏览器历史记录,也不需要轮询URL的改变,在可用性和性能上都做了很年夜的改观.它的基来源根基理年夜致是这样的,假设在域上有页面A.html和一个空白代办署理页面proxyA.html,另一个域上有个页面B.html和一个空白代办署理页面proxyB.html,A.html需要向B.html中发送消息时,页面会创立一个隐藏的iframe,iframe的src指向proxyB.html并把message作为URLfrag,由于B.html和proxyB.html是同域,所以在iframe加载完成之后,B.html可以获得iframe的URL,然后解析出message,并移除该iframe.当B.html需要向A.html发送消息时,原理一样.CrossFrame是很好的双向通信方式,而且平安高效,可是它在Opera中无法使用,不外在Opera下面我们可以使用更简单的window.postMessage来取代.
总结
跨域的方法很多,分歧的应用场景我们都可以找到一个最合适的解决方案.比如单向的数据请求,我们应该优先选择JSONP或者window.name,双向通信我们采用CrossFrame,在未与数据提供方没有告竣通信协议的情况下我们也可以用serverproxy的方式来抓取数据.
罕见的分歧域间的页面制约dom元素包括:
window.location可以设置,但不能读取.其它的location属性和方法被禁止访问; document.href可以设置,但不能读取.其它的document属性和方法被禁止访问;
创作时间:
二零二一年六月三十日
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- JavaScript 解决方案
![提示](https://static.bdocx.com/images/bang_tan.gif)