跨域 红太狼 2022-06-16 04:16 148阅读 0赞 ## ## # 什么是JS跨域访问? # 跨域是指 不同域名之间相互访问 例如 我的电脑上有2个服务器 192.168.0.11 192.168.0.12 如果第一个服务器上的页面要访问第二个服务器 就叫做跨域 或者http://www.baidu.com 要访问http://www.xxx.com 也是不同域名 也是跨域 . 域(Domain)是Windows网络中独立运行的单位,域之间相互访问则需要建立信任关系(即Trust Relation)。信任关系是连接在域与域之间的桥梁。当一个域与其他域建立了信任关系后,2个域之间不但可以按需要相互进行管理,还可以跨网分配文件和打印机等设备资源,使不同的域之间实现网络资源的共享与管理。 有一种简明的说法来解释广域跨域:跨域访问,简单来说就是 A 网站的 javascript 代码试图访问 B 网站,包括提交内容和获取内容。由于安全原因,跨域访问是被各大浏览器所默认禁止的。 ## ## ## ## ## [js中几种实用的跨域方法原理详解][js] ## 这里说的js跨域是指通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据,或者通过js获取页面中不同域的框架中(iframe)的数据。只要协议、域名、端口有任何一个不同,都被当作是不同的域。 下表给出了相对http://store.company.com/dir/page.html同源检测的结果: [![QQ截图20130613230631][QQ_20130613230631]][QQ_20130613230631_QQ_20130613230631] 要解决跨域的问题,我们可以使用以下几种方法: **一、通过jsonp跨域** 在js中,我们直接用XMLHttpRequest请求不同域上的数据时,是不可以的。但是,在页面上引入不同域上的js脚本文件却是可以的,jsonp正是利用这个特性来实现的。 比如,有个a.html页面,它里面的代码需要利用ajax获取一个不同域上的json数据,假设这个json数据地址是[http://example.com/data.php][http_example.com_data.php],那么a.html中的代码就可以这样: [![QQ截图20130613230631][QQ_20130613230631 1]][QQ_20130613230631_QQ_20130613230631 1] 我们看到获取数据的地址后面还有一个callback参数,按惯例是用这个参数名,但是你用其他的也一样。当然如果获取数据的jsonp地址页面不是你自己能控制的,就得按照提供数据的那一方的规定格式来操作了。 因为是当做一个js文件来引入的,所以[http://example.com/data.php][http_example.com_data.php]返回的必须是一个能执行的js文件,所以这个页面的php代码可能是这样的: [![QQ截图20130613230631][QQ_20130613230631 2]][QQ_20130613230631_QQ_20130613230631 2] 最终那个页面输出的结果是: [![QQ截图20130613230631][QQ_20130613230631 3]][QQ_20130613230631_QQ_20130613230631 3] 所以通过[http://example.com/data.php?callback=dosomething][http_example.com_data.php_callback_dosomething]得到的js文件,就是我们之前定义的dosomething函数,并且它的参数就是我们需要的json数据,这样我们就跨域获得了我们需要的数据。 这样jsonp的原理就很清楚了,通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。 知道jsonp跨域的原理后我们就可以用js动态生成script标签来进行跨域操作了,而不用特意的手动的书写那些script标签。如果你的页面使用jquery,那么通过它封装的方法就能很方便的来进行jsonp操作了。 [![QQ截图20130613230631][QQ_20130613230631 4]][QQ_20130613230631_QQ_20130613230631 4] 原理是一样的,只不过我们不需要手动的插入script标签以及定义回掉函数。jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。 **2、通过修改document.domain来跨子域** 浏览器都有一个同源策略,其限制之一就是第一种方法中我们说的不能通过ajax的方法去请求不同源中的文档。 它的第二个限制是浏览器中不同域的框架之间是不能进行js的交互操作的。有一点需要说明,不同的框架之间(父子或同辈),是能够获取到彼此的window对象的,但蛋疼的是你却不能使用获取到的window对象的属性和方法(html5中的postMessage方法是一个例外,还有些浏览器比如ie6也可以使用top、parent等少数几个属性),总之,你可以当做是只能获取到一个几乎无用的window对象。比如,有一个页面,它的地址是[http://www.example.com/a.html][http_www.example.com_a.html] , 在这个页面里面有一个iframe,它的src是[http://example.com/b.html][http_example.com_b.html], 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的: [![QQ截图20130613230631][QQ_20130613230631 5]][QQ_20130613230631_QQ_20130613230631 5] 这个时候,document.domain就可以派上用场了,我们只要把[http://www.example.com/a.html][http_www.example.com_a.html] 和 [http://example.com/b.html][http_example.com_b.html]这两个页面的document.domain都设成相同的域名就可以了。但要注意的是,document.domain的设置是有限制的,我们只能把document.domain设置成自身或更高一级的父域,且主域必须相同。例如:a.b.example.com 中某个文档的document.domain 可以设成a.b.example.com、b.example.com 、example.com中的任意一个,但是不可以设成 c.a.b.example.com,因为这是当前域的子域,也不可以设成baidu.com,因为主域已经不相同了。 在页面 [http://www.example.com/a.html][http_www.example.com_a.html] 中设置document.domain: [![QQ截图20130613230631][QQ_20130613230631 6]][QQ_20130613230631_QQ_20130613230631 6] 在页面 [http://example.com/b.html][http_example.com_b.html] 中也设置document.domain,而且这也是必须的,虽然这个文档的domain就是example.com,但是还是必须显示的设置document.domain的值: [![QQ截图20130613230631][QQ_20130613230631 7]][QQ_20130613230631_QQ_20130613230631 7] 这样我们就可以通过js访问到iframe中的各种属性和对象了。 不过如果你想在[http://www.example.com/a.html][http_www.example.com_a.html] 页面中通过ajax直接请求[http://example.com/b.html][http_example.com_b.html] 页面,即使你设置了相同的document.domain也还是不行的,所以修改document.domain的方法只适用于不同子域的框架间的交互。如果你想通过ajax的方法去与不同子域的页面交互,除了使用jsonp的方法外,还可以用一个隐藏的iframe来做一个代理。原理就是让这个iframe载入一个与你想要通过ajax获取数据的目标页面处在相同的域的页面,所以这个iframe中的页面是可以正常使用ajax去获取你要的数据的,然后就是通过我们刚刚讲得修改document.domain的方法,让我们能通过js完全控制这个iframe,这样我们就可以让iframe去发送ajax请求,然后收到的数据我们也可以获得了。 **3、使用window.name来进行跨域** window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置。 比如:有一个页面a.html,它里面有这样的代码: [![QQ截图20130613230631][QQ_20130613230631 8]][QQ_20130613230631_QQ_20130613230631 8] 再看看b.html页面的代码: [![QQ截图20130613230631][QQ_20130613230631 9]][QQ_20130613230631_QQ_20130613230631 9] a.html页面载入后3秒,跳转到了b.html页面,结果为: [![QQ截图20130613230631][QQ_20130613230631 10]][QQ_20130613230631_QQ_20130613230631 10] 我们看到在b.html页面上成功获取到了它的上一个页面a.html给window.name设置的值。如果在之后所有载入的页面都没对window.name进行修改的话,那么所有这些页面获取到的window.name的值都是a.html页面设置的那个值。当然,如果有需要,其中的任何一个页面都可以对window.name的值进行修改。注意,window.name的值只能是字符串的形式,这个字符串的大小最大能允许2M左右甚至更大的一个容量,具体取决于不同的浏览器,但一般是够用了。 上面的例子中,我们用到的页面a.html和b.html是处于同一个域的,但是即使a.html与b.html处于不同的域中,上述结论同样是适用的,这也正是利用window.name进行跨域的原理。 下面就来看一看具体是怎么样通过window.name来跨域获取数据的。还是举例说明。 比如有一个[www.example.com/a.html][http_www.example.com_a.html]页面,需要通过a.html页面里的js来获取另一个位于不同域上的页面[www.cnblogs.com/data.html][www.cnblogs.com_data.html]里的数据。 data.html页面里的代码很简单,就是给当前的window.name设置一个a.html页面想要得到的数据值。data.html里的代码: [![QQ截图20130613230631][QQ_20130613230631 11]][QQ_20130613230631_QQ_20130613230631 11] 那么在a.html页面中,我们怎么把data.html页面载入进来呢?显然我们不能直接在a.html页面中通过改变window.location来载入data.html页面,因为我们想要即使a.html页面不跳转也能得到data.html里的数据。答案就是在a.html页面中使用一个隐藏的iframe来充当一个中间人角色,由iframe去获取data.html的数据,然后a.html再去得到iframe获取到的数据。 充当中间人的iframe想要获取到data.html的通过window.name设置的数据,只需要把这个iframe的src设为[www.cnblogs.com/data.html][www.cnblogs.com_data.html]就行了。然后a.html想要得到iframe所获取到的数据,也就是想要得到iframe的window.name的值,还必须把这个iframe的src设成跟a.html页面同一个域才行,不然根据前面讲的同源策略,a.html是不能访问到iframe里的window.name属性的。这就是整个跨域过程。 看下a.html页面的代码: ![130623-20151207161022652-2118622654.png][] 上面的代码只是最简单的原理演示代码,你可以对使用js封装上面的过程,比如动态的创建iframe,动态的注册各种事件等等,当然为了安全,获取完数据后,还可以销毁作为代理的iframe。网上也有很多类似的现成代码,有兴趣的可以去找一下。 通过window.name来进行跨域,就是这样子的。 **4、使用HTML5中新引进的window.postMessage方法来跨域传送数据** window.postMessage(message,targetOrigin) 方法是html5新引进的特性,可以使用它来向其它的window对象发送消息,无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持window.postMessage方法。 调用postMessage方法的window对象是指要接收消息的那一个window对象,该方法的第一个参数message为要发送的消息,类型只能为字符串;第二个参数targetOrigin用来限定接收消息的那个window对象所在的域,如果不想限定域,可以使用通配符 \* 。 需要接收消息的window对象,可是通过监听自身的message事件来获取传过来的消息,消息内容储存在该事件对象的data属性中。 上面所说的向其他window对象发送消息,其实就是指一个页面有几个框架的那种情况,因为每一个框架都有一个window对象。在讨论第二种方法的时候,我们说过,不同域的框架间是可以获取到对方的window对象的,而且也可以使用window.postMessage这个方法。下面看一个简单的示例,有两个页面 [![QQ截图20130613230631][QQ_20130613230631 12]][QQ_20130613230631_QQ_20130613230631 12] [![QQ截图20130613230631][QQ_20130613230631 13]][QQ_20130613230631_QQ_20130613230631 13] 我们运行a页面后得到的结果: [![QQ截图20130613230631][QQ_20130613230631 14]][QQ_20130613230631_QQ_20130613230631 14] 我们看到b页面成功的收到了消息。 使用postMessage来跨域传送数据还是比较直观和方便的,但是缺点是IE6、IE7不支持,所以用不用还得根据实际需要来决定。 **结语:** 除了以上几种方法外,还有flash、在服务器上设置代理页面等跨域方式,这里就不做介绍了。 以上四种方法,可以根据项目的实际情况来进行选择应用,个人认为window.name的方法既不复杂,也能兼容到几乎所有浏览器,这真是极好的一种跨域方法。 [js]: http://www.cnblogs.com/2050/p/3191744.html [QQ_20130613230631]: http://images.cnitblog.com/blog/130623/201307/15184526-1cfb09aa81c742c3bc80e56474ed4e74.png [QQ_20130613230631_QQ_20130613230631]: /images/20220616/cd7df5c66842454ca333b56eb03b0c82.png [http_example.com_data.php]: http://example.com/data.php [QQ_20130613230631 1]: http://images.cnitblog.com/blog/130623/201307/15184527-4a8d6daf1de24478bd492441755ee5d4.png [QQ_20130613230631_QQ_20130613230631 1]: /images/20220616/7eefceca115545e4a150fbd8af3f67ad.png [QQ_20130613230631 2]: http://images.cnitblog.com/blog/130623/201307/15184528-5bc01c7fb57c474ca6fafa6edd09218d.png [QQ_20130613230631_QQ_20130613230631 2]: /images/20220616/b884ba6704504f9ebe03ff872609e2b7.png [QQ_20130613230631 3]: http://images.cnitblog.com/blog/130623/201307/15184529-57760c8711a54fde9839b5934d8bddd0.png [QQ_20130613230631_QQ_20130613230631 3]: /images/20220616/4e036b3b9f854bf8b7ab8bda25fb6cc9.png [http_example.com_data.php_callback_dosomething]: http://example.com/data.php?callback=dosomething [QQ_20130613230631 4]: http://images.cnitblog.com/blog/130623/201307/15184530-1072ef43c61b4f169eaabd2dfdfde7ef.png [QQ_20130613230631_QQ_20130613230631 4]: /images/20220616/a7a8cdd260cd4120bc53d20366c8e055.png [http_www.example.com_a.html]: http://www.example.com/a.html [http_example.com_b.html]: http://example.com/b.html [QQ_20130613230631 5]: http://images.cnitblog.com/blog/130623/201307/15184531-3bc04aa442d9494bae8dc1f325513893.png [QQ_20130613230631_QQ_20130613230631 5]: /images/20220616/2edb4e3d4ad2412f8760eed507bdb68a.png [QQ_20130613230631 6]: http://images.cnitblog.com/blog/130623/201307/15184532-ad98082ee5044921b1b667f1ec2b822b.png [QQ_20130613230631_QQ_20130613230631 6]: /images/20220616/8771cca8fbf84941bb625dac51d9a897.png [QQ_20130613230631 7]: http://images.cnitblog.com/blog/130623/201307/15184533-aaa37d1a446f4ff2871d9e2b3e9477da.png [QQ_20130613230631_QQ_20130613230631 7]: /images/20220616/c8eb097927204488b40d0f47afe4f6c8.png [QQ_20130613230631 8]: http://images.cnitblog.com/blog/130623/201307/15184534-ebbe36523151419cb20df7beb37c277a.png [QQ_20130613230631_QQ_20130613230631 8]: /images/20220616/b38ea843315b47faa9ea4b71b6c6ffce.png [QQ_20130613230631 9]: http://images.cnitblog.com/blog/130623/201307/15184535-b6c0bc2e37df40f1ae3b113a08e9edb4.png [QQ_20130613230631_QQ_20130613230631 9]: /images/20220616/19464157fab34af3bff8385782c0320e.png [QQ_20130613230631 10]: http://images.cnitblog.com/blog/130623/201307/15184537-26ab92ec8cdc444f8b9fa6fc62ed78fb.png [QQ_20130613230631_QQ_20130613230631 10]: /images/20220616/6ddf5629663544c691335662a02256a1.png [www.cnblogs.com_data.html]: http://www.cnblogs.com/data.html [QQ_20130613230631 11]: http://images.cnitblog.com/blog/130623/201307/15184539-7a190a2eb9d5464787a124f5e2c6a06d.png [QQ_20130613230631_QQ_20130613230631 11]: /images/20220616/605a4151321942c7abedb2d7558c043e.png [130623-20151207161022652-2118622654.png]: /images/20220616/eb5dddb567a142c19aeef80de8635544.png [QQ_20130613230631 12]: http://images.cnitblog.com/blog/130623/201307/15184545-4d435286d9974c65890ececbce8be9b7.png [QQ_20130613230631_QQ_20130613230631 12]: /images/20220616/0ce764c349904572b24fc29eb7f48067.png [QQ_20130613230631 13]: http://images.cnitblog.com/blog/130623/201307/15184546-6d54ada26b1a47cc8d856b0cd90d6017.png [QQ_20130613230631_QQ_20130613230631 13]: /images/20220616/632dc49dd81847c4999b42689915ef92.png [QQ_20130613230631 14]: http://images.cnitblog.com/blog/130623/201307/15184547-c3c3317b3a674b9c8bfb65b1898e1829.png [QQ_20130613230631_QQ_20130613230631 14]: /images/20220616/bb3c27a3098d46dd8aced75b21751302.png
相关 跨域、跨域问题 跨域(CORS)是一种允许当前域(domain)的资源(比如html/js/web service)被其他域(domain)的脚本请求访问的机制,通常由于同域安全策略(the 朴灿烈づ我的快乐病毒、/ 2023年09月27日 00:59/ 0 赞/ 106 阅读
相关 跨域 ![20200713130140692.png][] delete再次忘了加/横线 又来了 跨域错误 ![watermark_type_ZmFuZ3poZW5naGV 比眉伴天荒/ 2023年02月25日 14:29/ 0 赞/ 185 阅读
相关 跨域 什么是JS跨域访问? 跨域是指 不同域名之间相互访问 例如 我的电脑上有2个服务器 192.168.0.11 192.168.0.12 如 红太狼/ 2022年06月16日 04:16/ 0 赞/ 149 阅读
相关 跨域与跨域访问 转自:http://blog.csdn.net/notechsolution/article/details/50394391 什么是跨域 跨域是指从一个域名的网页 淡淡的烟草味﹌/ 2022年06月14日 09:26/ 0 赞/ 291 阅读
相关 跨域 跨域,指的是浏览器不能执行其他网站的脚本。它是由浏览器的同源策略造成的,是浏览器对javascript施加的安全限制。 所谓同源是指,域名,协议,端口均相同 ![20171 冷不防/ 2022年06月03日 02:50/ 0 赞/ 181 阅读
相关 跨域 jsonp: $(function()\{ $.ajax(\{ async: false, type: "GET", dataType 绝地灬酷狼/ 2022年05月29日 01:29/ 0 赞/ 196 阅读
相关 跨域 CORS支持所有类型的HTTP请求,是跨域HTTP请求的根本解决方案 JSONP只支持GET请求,JSONP的优势在于支持老式浏览器,以及可以向不支持CORS的网站请求数据。 墨蓝/ 2022年02月28日 07:24/ 0 赞/ 467 阅读
相关 跨域 1、同源: 同源策略是浏览器的一种安全策略,所谓同源是指,域名,协议,端口号完全相同 1.1目的:保护用户信息安全 1.2限制:cookie、localSto Myth丶恋晨/ 2022年01月20日 04:35/ 0 赞/ 253 阅读
相关 跨域 2018-07-11 发布 [不要再问我跨域的问题了][Link 1] [javascript][] [前端][Link 2] 野性酷女/ 2021年12月18日 14:59/ 0 赞/ 269 阅读
相关 跨域 引言: 简单说跨域就是A网站调用B网站的程序,获取对应的数据;但是受制于同源策略,这样是不可行的,但是有时候我们有时候又需要这样的情境进行使用 复制代码 同 超、凢脫俗/ 2021年07月25日 23:50/ 0 赞/ 443 阅读
还没有评论,来说两句吧...