前端跨域问题

在工作中,经常会遇到js跨域问题,特别是ajax请求的时候。现在整理一下,并从网上找一些 全一点的解决办法。留着以后用

首先什么是跨域,简单地理解就是因为JavaScript同源策略的限制,a.com 域名下的js无法操作b.com或是c.a.com域名下的对象。更详细的说明可以看下表:

URL说明是否允许通信
http://www.a.com/a.js
http://www.a.com/b.js
同一域名下允许
http://www.a.com/lab/a.js
http://www.a.com/script/b.js
同一域名下不同文件夹允许
http://www.a.com:8000/a.js
http://www.a.com/b.js
同一域名,不同端口不允许
http://www.a.com/a.js
https://www.a.com/b.js
同一域名,不同协议不允许
http://www.a.com/a.js
http://70.32.92.74/b.js
域名和域名对应ip不允许
http://www.a.com/a.js
http://script.a.com/b.js
主域相同,子域不同不允许
http://www.a.com/a.js
http://a.com/b.js
同一域名,不同二级域名(同上)不允许(cookie这种情况下也不允许访问)
http://www.cnblogs.com/a.js
http://www.a.com/b.js
不同域名不允许
特别注意两点:
第一,如果是协议和端口造成的跨域问题“前台”是无能为力的,
第二:在跨域问题上,域仅仅是通过“URL的首部”来识别而不会去尝试判断相同的ip地址对应着两个域或两个域是否在同一个ip上。
“URL的首部”指window.location.protocol +window.location.host,也可以理解为“Domains, protocols and ports must match”。

接下来简单地总结一下在“前台”一般处理跨域的办法,后台proxy这种方案牵涉到后台配置,这里就不阐述了,有兴趣的可以看看yahoo的这篇文章:《JavaScript: Use a Web Proxy for Cross-Domain XMLHttpRequest Calls》

1、document.domain+iframe的设置

对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。具体的做法是可以在http://www.a.com/a.html和http://script.a.com/b.html两个文件中分别加上document.domain = ‘a.com’;然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以“交互”了。当然这种办法只能解决主域相同而二级域名不同的情况,如果你异想天开的把script.a.com的domian设为alibaba.com那显然是会报错地!代码如下:

www.a.com上的a.html

document.domain = 'a.com';
var ifr = document.createElement('iframe');
ifr.src = 'http://script.a.com/b.html';
ifr.style.display = 'none';
document.body.appendChild(ifr);
ifr.onload = function(){var doc = ifr.contentDocument || ifr.contentWindow.document;// 在这里操纵b.htmlalert(doc.getElementsByTagName("h1")[0].childNodes[0].nodeValue);
};

script.a.com上的b.html

document.domain = 'a.com';

这种方式适用于{www.kuqin.com, kuqin.com, script.kuqin.com, css.kuqin.com}中的任何页面相互通信。

备注:某一页面的domain默认等于window.location.hostname。主域名是不带www的域名,例如a.com,主域名前面带前缀的通常都为二级域名或多级域名,例如www.a.com其实是二级域名。 domain只能设置为主域名,不可以在b.a.com中将domain设置为c.a.com。

问题:1、安全性,当一个站点(b.a.com)被攻击后,另一个站点(c.a.com)会引起安全漏洞。

    2、如果一个页面中引入多个iframe,要想能够操作所有iframe,必须都得设置相同domain。

2、动态创建script

虽然浏览器默认禁止了跨域访问,但并不禁止在页面中引用其他域的JS文件,并可以自由执行引入的JS文件中的function(包括操作cookie、Dom等等)。根据这一点,可以方便地通过创建script节点的方法来实现完全跨域的通信。具体的做法可以参考YUI的Get Utility

这里判断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;}
};

3、利用iframe和location.hash

这个办法比较绕,但是可以解决完全跨域情况下的脚步置换问题。原理是利用location.hash来进行传值。在url: http://a.com#helloword中的‘#helloworld’就是location.hash,改变hash并不会导致页面刷新,所以可以利用hash值来进行数据传递,当然数据容量是有限的。假设域名a.com下的文件cs1.html要和cnblogs.com域名下的cs2.html传递信息,cs1.html首先创建自动创建一个隐藏的iframe,iframe的src指向cnblogs.com域名下的cs2.html页面,这时的hash值可以做参数传递用。cs2.html响应请求后再将通过修改cs1.html的hash值来传递数据(由于两个页面不在同一个域下IE、Chrome不允许修改parent.location.hash的值,所以要借助于a.com域名下的一个代理iframe;Firefox可以修改)。同时在cs1.html上加一个定时器,隔一段时间来判断location.hash的值有没有变化,一点有变化则获取获取hash值。代码如下:

先是a.com下的文件cs1.html文件:

function startRequest(){var ifr = document.createElement('iframe');ifr.style.display = 'none';ifr.src = 'http://www.cnblogs.com/lab/cscript/cs2.html#paramdo';document.body.appendChild(ifr);
}function checkHash() {try {var data = location.hash ? location.hash.substring(1) : '';if (console.log) {console.log('Now the data is '+data);}} catch(e) {};
}
setInterval(checkHash, 2000);

cnblogs.com域名下的cs2.html:

//模拟一个简单的参数处理操作
switch(location.hash){case '#paramdo':callBack();break;case '#paramset'://do something……break;
}function callBack(){try {parent.location.hash = 'somedata';} catch (e) {// ie、chrome的安全机制无法修改parent.location.hash,// 所以要利用一个中间的cnblogs域下的代理iframevar ifrproxy = document.createElement('iframe');ifrproxy.style.display = 'none';ifrproxy.src = 'http://a.com/test/cscript/cs3.html#somedata';    // 注意该文件在"a.com"域下document.body.appendChild(ifrproxy);}
}

a.com下的域名cs3.html

//因为parent.parent和自身属于同一个域,所以可以改变其location.hash的值
parent.parent.location.hash = self.location.hash.substring(1);

当然这样做也存在很多缺点,诸如数据直接暴露在了url中,数据容量和类型都有限等……

 

 

4、window.name实现的跨域数据传输

有三个页面:

  • a.com/app.html:应用页面。
  • a.com/proxy.html:代理文件,一般是一个没有任何内容的html文件,需要和应用页面在同一域下。
  • b.com/data.html:应用页面需要获取数据的页面,可称为数据页面。

实现起来基本步骤如下:

  1. 在应用页面(a.com/app.html)中创建一个iframe,把其src指向数据页面(b.com/data.html)。
    数据页面会把数据附加到这个iframe的window.name上,data.html代码如下:
    <script type="text/javascript">window.name = 'I was there!';    // 这里是要传输的数据,大小一般为2M,IE和firefox下可以大至32M左右// 数据格式可以自定义,如json、字符串
    </script>
  2. 在应用页面(a.com/app.html)中监听iframe的onload事件,在此事件中设置这个iframe的src指向本地域的代理文件(代理文件和应用页面在同一域下,所以可以相互通信)。app.html部分代码如下:
    <script type="text/javascript">var state = 0, iframe = document.createElement('iframe'),loadfn = function() {if (state === 1) {var data = iframe.contentWindow.name;    // 读取数据alert(data);    //弹出'I was there!'} else if (state === 0) {state = 1;iframe.contentWindow.location = "http://a.com/proxy.html";    // 设置的代理文件}  };iframe.src = 'http://b.com/data.html';if (iframe.attachEvent) {iframe.attachEvent('onload', loadfn);} else {iframe.onload  = loadfn;}document.body.appendChild(iframe);
    </script>
  3. 获取数据以后销毁这个iframe,释放内存;这也保证了安全(不被其他域frame js访问)。
    <script type="text/javascript">iframe.contentWindow.document.write('');iframe.contentWindow.close();document.body.removeChild(iframe);
    </script>

总结起来即:iframe的src属性由外域转向本地域,跨域数据即由iframe的window.name从外域传递到本地域。这个就巧妙地绕过了浏览器的跨域访问限制,但同时它又是安全操作。

 

 我在做异步表单提交跨域的时候用到了jquery.form.js这个插件,可以解决跨域的问题

5、使用HTML5 postMessage

HTML5中最酷的新功能之一就是 跨文档消息传输Cross Document Messaging。下一代浏览器都将支持这个功能:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 。 Facebook已经使用了这个功能,用postMessage支持基于web的实时消息传递。

otherWindow.postMessage(message, targetOrigin);
otherWindow: 对接收信息页面的window的引用。可以是页面中iframe的contentWindow属性;window.open的返回值;通过name或下标从window.frames取到的值。
message: 所要发送的数据,string类型。
targetOrigin: 用于限制otherWindow,“*”表示不作限制

a.com/index.html中的代码:

<iframe id="ifr" src="b.com/index.html"></iframe>
<script type="text/javascript">
window.onload = function() {var ifr = document.getElementById('ifr');var targetOrigin = 'http://b.com';  // 若写成'http://b.com/c/proxy.html'效果一样// 若写成'http://c.com'就不会执行postMessage了ifr.contentWindow.postMessage('I was there!', targetOrigin);
};
</script>

b.com/index.html中的代码:

<script type="text/javascript">window.addEventListener('message', function(event){// 通过origin属性判断消息来源地址if (event.origin == 'http://a.com') {alert(event.data);    // 弹出"I was there!"alert(event.source);  // 对a.com、index.html中window对象的引用// 但由于同源策略,这里event.source不可以访问window对象}}, false);
</script>

6、ACCESS CONTROL

     Access Control是比较超越的跨域方式,目前只在很少的浏览器中得以支持,这些浏览器可以发送一个跨域的HTTP请求(Firefox, Google Chrome等通过XMLHTTPRequest实现,IE8下通过XDomainRequest实现),请求的响应必须包含一个Access- Control-Allow-Origin的HTTP响应头,该响应头声明了请求域的可访问权限。例如www.a.com对www.b.com下的 asset.php发送了一个跨域的HTTP请求,那么asset.php必须加入如下的响应头:header("Access-Control-Allow-Origin: http://www.a.com%22);%7f/
7、JSONP

JSONP原理

 

JSONP的实现原理,这里简单讲就是HTML里面所有带src属性的标签都可以跨域,如iframe,img,script等。

 

所以可以把需要跨域的请求改成用script脚本加载即可,服务器返回执行字符串,但是这个字符串是在window全局作用域下执行的,你需要把他返回到你的代码的作用域内,这里就需要临时创建一个全局的回调函数,并把到传到后台,最后再整合实际要请求的数组,返回给前端,让浏览器直接调用,用回调的形式回到你的原代码流程中。 

<script type="text/javascript">    

    function jsonpCallback(result) {    

       for(var i in result) {    

     alert(i+":"+result[i]);//循环输出a:1,b:2,etc.    

        }    

    }    

    var JSONP=document.createElement("script");    

  JSONP.type="text/javascript";    

  JSONP.src="http://crossdomain.com/services.php?callback=jsonpCallback";    

  document.getElementsByTagName("head")[0].appendChild(JSONP);    

</script>   

 

转自:http://www.cnblogs.com/rainman/archive/2011/02/20/1959325.html

  http://www.cnblogs.com/rainman/archive/2011/02/21/1960044.html

转载于:https://www.cnblogs.com/myzy/p/5230326.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/295198.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

javascript Date format(js日期格式化)

// 对Date的扩展&#xff0c;将 Date 转化为指定格式的String// 月(M)、日(d)、小时(h)、分(m)、秒(s)、季度(q) 可以用 1-2 个占位符&#xff0c;// 年(y)可以用 1-4 个占位符&#xff0c;毫秒(S)只能用 1 个占位符(是 1-3 位的数字)// 例子&#xff1a;// (new Date()).Forma…

php json.parse,JSON.parse()与JSON.stringify()和eval()使用方法详解

这次给大家带来JSON.parse()与JSON.stringify()和eval()使用方法详解&#xff0c;JSON.parse()与JSON.stringify()和eval()使用的注意事项有哪些&#xff0c;下面就是实战案例&#xff0c;一起来看一下。“JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。它基于…

部署webservice到远程服务器

在本地编写好webservice后并在本机验证正确后&#xff0c;在本地发布后&#xff0c;直接将发布时设置的文件夹复制到远程服务器上&#xff0c;在远程服务器的IIS上默认网站->新建虚拟目录->设置别名->物理路径设置好 &#xff0c;别人就可以直接在web浏览器输入“IP别…

无需Windbg | 使用VS 2019调试.NET程序的Crash异常

前言某台服务器上的IIS应用程序池&#xff0c;最近经常会自动关闭。查看服务器上的事件日志&#xff0c;发现在关闭时&#xff0c;w3p.exe抛出了stackoverflow异常。幸好&#xff0c;Windows自动帮我们抓取了Crash的dump文件&#xff1a;一般来说&#xff0c;我们会使用windbg来…

被夸了几十年,地球都要因为它变秃了,你还天天用它......

全世界只有3.14 % 的人关注了爆炸吧知识纸袋的流行不是环保要的结果模友们&#xff0c;“限塑令”在中国已经实行12年了&#xff0c;惊讶不&#xff1f;经过12年的努力&#xff0c;塑料袋终于不在大街上明目张胆的漫天飞舞。超模君相信大家都有一个共同认知&#xff1a;塑料袋污…

LeetCode之Add Two Numbers

LeetCode之Add Two Numbers 题目:You are given two linked lists representing two non-negative numbers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. Input: (2 ->…

windows消息机制

windows消息机制转载于:https://www.cnblogs.com/LoveFishC/archive/2012/08/28/3846744.html

php round 取余,PHP round() 函数

PHP round() 函数实例对浮点数进行四舍五入&#xff1a;<?php echo(round(0.60) . ""); echo(round(0.50) . ""); echo(round(0.49). ""); echo(round(-4.40) . ""); echo(round(-4.60)); ?>定义和用法round() 函数对浮点数进…

Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)(转)

互联网的发展&#xff0c;网站应用的规模不断扩大&#xff0c;常规的垂直应用架构已无法应对&#xff0c;分布式服务架构以及流动计算架构势在必行&#xff0c;Dubbo是一个分布式服务框架&#xff0c;在这种情况下诞生的。现在核心业务抽取出来&#xff0c;作为独立的服务&…

孤掌难鸣-------堵水眼

序言: 一口水平井&#xff0c;井斜已经52度&#xff0c;方位在水平井的连线方向上。此段为增斜段&#xff0c;多次钻具组合的调整就为了正钻轨迹符合设计轨迹。然而在更换钻具组合下到底后&#xff0c;出现了两趟钻“堵水眼”的现象&#xff0c;第一次运气好顶开&#xff0c;而…

技术分享 | 一条神奇的曲线——贝塞尔曲线在前端的应用

源宝导读&#xff1a;在前端的开发中我们经常会遇到利用贝塞尔曲线帮助我们完成前端的动画和图形绘制&#xff0c;但是对其中的一些参数配置是一头雾水。本文将从贝塞尔曲线的原理讲起&#xff0c;由浅入深剖析一阶到多阶贝塞尔的实现原理&#xff0c;最后从三个方向来介绍它的…

链表之单、双链表反序

给定一个单链表,然后对它反序。 ListNode类 public class ListNode {int val;ListNode next;ListNode(int x){val=x;next=null;}ListNode(){}ListNode(int x,ListNode node){val=x;next=node;}public void setVal(int val){this.val=val;}public int getVal(){return val;}pu…

女生来大姨妈该怎么哄她?

1 这捞人速度&#xff01;▼2 老师&#xff1a;我怀疑你在内涵我&#xff01;&#xff1f;&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 就很出戏&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 分手到底有多痛苦&#xff1f;▼5 家长会上看到的纸…

junit问题

在junit中写了个测试类&#xff0c;测试数据库相关操作&#xff0c;结果在执行时&#xff0c;出现Caused by: javax.xml.parsers.FactoryConfigurationError: Provider org.apache.xerces.jaxp.DocumentBuilderFactoryImpl not found的错误&#xff0c;这是缺少了xercesImpl.ja…

C#的7个原则

C#的七个原则如下&#xff1a; 1.单一职责原则(Single Responsibility Principle, SRP)&#xff1a;一个类只负责一个功能领域中的相应职责。 2.开闭原则(Open-Closed Principle, OCP)&#xff1a;软件实体应对扩展开放&#xff0c;而对修改关闭。 3.里氏代换原则(Liskov Subst…

OAuth 2.1 的进化之路

背景2010年, OAuth 授权规范 1.0 (rfc 5849) 版本发布, 2年后, 更简单易用的 OAuth 2.0 规范发布&#xff08;rfc 6749&#xff09;, 这也是大家最熟悉并且在互联网上使用最广泛的版本, 在2012年的时候, iPhone 5 是全新的, 微软最新的浏览器还是 IE9, 单页面应用在当时还被称作…

php中怎样表示组合框,php – 如何实现动态组合框选择系统

诀窍是订阅更改事件并相应地重置第二个框的内容.HTML&#xff1a;- select -NokiaAppleJavaScript(准备好了)&#xff1a;var selectBrand $("#brand");var selectType $("#type");var optionsList {nokia: ["C6-01","E7-00"],appl…

用beyond compare解决git不能同步项目重新下载项目然后就行对比解决冲突

用beyond compare解决git不能同步项目重新下载项目然后就行对比解决冲突 这几天一直由于之前的的项目实现的功能没有提交,git客户端我用的是smartGit,然后用着用着需要那个licesenc,反正要一个有效的生成文件,然后我就想解决办法。 方法一: 我就到网上找,csd…

中科院超牛的物理学家,摇滚界无人不知的“李白”,你一定听过他的歌!

全世界只有3.14 % 的人关注了爆炸吧知识一个热爱音乐的科研工作者最近&#xff0c;有不少模友在后台问&#xff0c;如何如何去平衡好学习/工作和兴趣爱好之间的关系&#xff1f;很多人会说这么简单的问题&#xff0c;为什么还要问&#xff1f;其实并不简单&#xff0c;在现实生…

Nginx源码安装及应用

一&#xff1a;Nginx简介&#xff1a; Nginx ("engine x") 是一个高性能的HTTP和反向代理服务器。在高连接并发的情况下&#xff0c;Nginx是Apache服务器不错的替代品。 Nginx作为负载均衡服务器&#xff1a;Nginx 既可以在内部直接支持Rails和PHP 程序对外进行服务&…