常见的跨域方式及原理-第一篇

本文详细介绍了三种常见的跨域解决方案:JSONP利用script标签的特性实现跨域通信;document.domain设置相同子域名实现不同子域间框架的交互;window.name利用窗口的name属性在不同域的页面间传递数据。每种方法的原理、示例及应用场景均有阐述。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

跨域:通过js在不同的域之间进行数据传输或通信,比如用ajax向一个不同的域请求数据或者通过js获取页面中不同域的框架(iframe)中的数据。只要协议、域名、端口有任何一个不同,都被当作是跨域。

下表给出了相对http://store.company.com/dir/page.html同源检测的结果:
这里写图片描述

跨域解决方法:
一、jsonp
跨域原理:利用script标签没有跨域限制,实现跨域目的
示例:a.html页面需要获取不同域上的json数据,这个json数据地址是http://example.com/data.php,代码如下
a.html
这里写图片描述

data.php
这里写图片描述

最终结果
这里写图片描述

解析:
通过script标签引入一个js文件,这个js文件载入成功后会执行我们在url参数中指定的函数,并且会把我们需要的json数据作为参数传入。所以jsonp是需要服务器端的页面进行相应的配合的。


jquery做法;
这里写图片描述

解析:
原理是一样的,只不过我们不需要手动的插入script标签以及定义回掉函数。jquery会自动生成一个全局函数来替换callback=?中的问号,之后获取到数据后又会自动销毁,实际上就是起一个临时代理函数的作用。$.getJSON方法会自动判断是否跨域,不跨域的话,就调用普通的ajax方法;跨域的话,则会以异步加载js文件的形式来调用jsonp的回调函数。


二、document.domain
背景描述:浏览器都有一个同源策略,其限制之一就是不能用ajax的方法去请求不同源中文档;第二个限制是浏览器中不同域的框架之间是不能进行js的交互操作的;
但是不同框架之间(父子或同辈),是能购获取到彼此的window对象的,但是不能获取到window对象的属性和方法,可以说是只能获取到一个几乎无用的window对象。
比如,有一个页面,它的地址是http://www.example.com/a.html , 在这个页面里面有一个iframe,它的src是http://example.com/b.html, 很显然,这个页面与它里面的iframe框架是不同域的,所以我们是无法通过在页面中书写js代码来获取iframe中的东西的。
这个时候,document.domain就可以派上用场了,我们只要把http://www.example.com/a.htmlhttp://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,因为主域已经不相同了。

跨域原理:通过将不同子域名的document.domain属性设置为相同的父域名,来实现不同子域名之间的跨域通信。

示例:
在页面 http://www.example.com/a.html 中设置document.domain:
这里写图片描述
在页面 http://example.com/b.html 中也设置document.domain,而且这也是必须的,虽然这个文档的domain就是example.com,但是还是必须显示的设置document.domain的值:
这里写图片描述
这样我们就可以通过js访问到iframe中的各种属性和对象了。

注意:如果你想在http://www.example.com/a.html 页面中通过ajax直接请求http://example.com/b.html 页面,即使你设置了相同的document.domain也还是不行的,所以修改document.domain的方法只适用于不同子域的框架间的交互。


三、window.name
跨域原理:window对象有个name属性,该属性有个特征:即在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,并不会因新页面的载入而进行重置,即使是不同域间也是适用的。

注意:window.name的值只能是字符串的形式,最大能允许2M左右或者更大,具体取决于不同的浏览器,但一般是够用了

示例:
1、同一个域下
a.html
这里写图片描述

b.html
这里写图片描述

结果
这里写图片描述


2、不同域下
比如有一个http://www.myapp.com/window_name_test.ejs页面,需要通过js来获取另一个位于不同域上的页面http://www.otherapp.com/window_iframe里的数据。

访问页面:http://www.myapp.com/window_name_test.ejs

<button>发送消息</button>
  <div class="req"></div>
  <div class="res"></div>
  <script>
    function sendMsg(msg) {
      var state = 0, data;
      var frame = document.createElement("frame");
      var baseProxy = "http://www.otherapp.com/window_iframe";
      var request = {data: msg};
      frame.src = baseProxy + "#" + encodeURI(JSON.stringify(request));
      frame.style.display = "none";
      frame.onload = function() {
        if (state === 1) {
          data = frame.contentWindow.name;
          document.querySelector('.res').innerHTML = "获得响应:" + data;
          // 删除iframe
          frame.contentWindow.document.write('');
          frame.contentWindow.close();
          document.body.removeChild(frame);
        } else {
          state = 1;
          frame.src = "http://www.myapp.com/window_iframe";
        }
      };
      document.body.appendChild(frame);
    }
    document.querySelector('button').onclick = function() {
      var val = Math.random();
      sendMsg(val);
      document.querySelector('.req').innerHTML = "请求数据:" + val;
    }
  </script>
跨域iframe:http://www.myapp.com/window_iframe

  <script>
    var hash = window.location.hash;
    if (hash && hash.length > 1) {
      var request = hash.slice(1, hash.length);
      var obj = JSON.parse(decodeURI(request));
      var data = obj.data;
      window.name = data*100;
    }
  </script>

解析:
使用一个隐藏的iframe充当一个中间人的角色,先创建一个隐藏的iframe b,将b指向外部资源服务;
b加载完成之后,将相应的数据附加到window.name上;
目前a和b不同源,a还是不能获取到b的window.name;所以在b获取到数据之后,将页面导航到任何一个与a同源的页面,这时a就可以获取到b的name值;当a获取到数据之后,就可以随时删掉b

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值