JavaScript 跨域怎么实现?如何解决跨域问题?

🌙
手机阅读
本文目录结构

问题

跨域怎么实现?如何解决跨域问题?

答案

  • jsonp、jsonp的原理是动态插入script标签

  • document.domain+iframe、

  • window.name、window.postMessage、

服务器上设置代理页面;

具体的如下;

javascript跨域有两种情况: 

  • 1、基于同一父域的子域之间,如:a.c.com和b.c.com 
  • 2、基于不同的父域之间,如:www.a.com和www.b.com 
  • 3、端口的不同,如:www.a.com:8080和www.a.com:8088 
  • 4、协议不同,如:http://www.a.comhttps://www.a.com

对于情况3和4,需要通过后台proxy来解决,具体方式如下: 

  • a、在发起方的域下创建proxy程序 
  • b、发起方的js调用本域下的proxy程序 
  • c、proxy将请求发送给接收方并获取相应数据 
  • d、proxy将获得的数据返回给发起方的js 

代码和ajax调用一致,其实这种方式就是通过ajax进行调用的

而情况1和2除了通过后台proxy这种方式外,还可以有多种办法来解决: 

1、document.domain+iframe(只能解决情况1): 

  • a、在发起方页面和接收方页面设置document.domain,并将值设为父域的主域名(window.location.hostname) 
  • b、在发起方页面创建一个隐藏的iframe,iframe的源是接收方页面 
  • c、根据浏览器的不同,通过iframe.contentDocument || iframe.contentWindow.document来获得接收方页面的内容 
  • d、通过获得的接收方页面的内容来与接收方进行交互 

这种方法有个缺点,就是当一个域被攻击时,另一个域会有安全漏洞出现。 

//发起方
document.domain = 'a.com';
var src = document.getElementById('txtSrc').value;
var ifr = document.createElement('iframe');
ifr.src = src;
ifr.style.display = 'none';
document.body.appendChild(ifr);
function GetDataFromDomain () {
  var doc = ifr.contentDocument || ifr.contentWindow.document;
  console.log(doc.getElementById('data').value)
}

//接收方
document.domain = 'a.com'

https://a.axihe.com/focus/js/http/http-18-01.png

2、 动态创建script(也就是jsonp)

  • a、在发起方页面动态加载一个script,script的URL指向接收方的一个处理地址(后台),该地址返回的javascript方法会被执行,另外URL中可以传入一些参数,该方法只支持GET方式提交参数。

  • b、加载的script可以在调用跨域js方法后再做一些自己的处理

//发起方
function load_script (callback) {
  var head = document.getElementsByTagName('head')[0];
  var script = document.createElement('script');
  var src = document.getElementById('txtSrc').value;

  script.type = 'text/javascript';
  script.src = src;

  // 借鉴 jquery 的 script跨域方法
  script.onload = script.onreadystatechange = function () {
    if (
      !this.readyState ||
      this.readyState === 'loaded' ||
      this.readyState == 'complete'
    ) {
      callback && callback();
      script.onload = script.onreadystatechange = null;
      if (head && script.parentNode) {
        head.removeChild(script);
      }
    }
  }
  head.insertBefore(script, head.firstChild);
}

https://a.axihe.com/focus/js/http/http-18-02.png

3、location.hash+iframe: 

  • a、发起方创建一个隐藏的iframe,iframe的源指向接收方的页面,并通过接收方页面的hash值来传送数据 
  • b、发起方创建一个定时器,定时检查自己的location.hash并作相应的处理 
  • c、接收方创建一个隐藏的iframe,iframe的源指向发起方所在域的一个代理页面,并将接收方根据发起方传入的数据而处理后的数据通过代理页面的hash值来传送 
  • d、接收方创建一个定时器,定时检查自己的location.hash并作相应的处理 
  • e、代理页面创建一个定时器,定时检查自己的location.hash并同步更新发起方页面的hash值 www.a.com/a.html#aaa,其中#aaa就是location.hash值 

https://a.axihe.com/focus/js/http/http-18-03.png

https://a.axihe.com/focus/js/http/http-18-03-2.png

4、window.name:

  • a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面 
  • b、接收方在自己页面通过script将需要传送的数据放入window.name里 
  • c、发起方在iframe的onload方法里将iframe的源改为和自己在同一个域下的代理页面(因为只能是同一个域下才能访问window.name的值) 
  • d、获取window.name的值(虽然iframe的源改变了,但是window.name的值不会变) 
  • window.name的值差不多可以有2MB大小

https://a.axihe.com/focus/js/http/http-18-04.png

5、HTML5的postMessage 

  • a、receiverWindow.postMessage(msg, targetOrigin),receiverWindow就是对接收消息的window的引用,可以是iframe的contentWindow/window.open的返回值/window.frames中的一个;msg就是要发送的消息,string类型;targetOrigin用于限制receiverWindow的URI,包括主域名和端口,使用“*”表示无限制,但是为了安全起见还是需要设置下,以防把消息发送给恶意的网站,如果targetOrigin的URI和receiverWindow的不符,则放弃发送消息。 

  • b、接收方通过message事件来获得消息,并且通过event.origin的属性来验证发送方并通过event.data来获得传送的消息内容,event.source来获得发送方的window对象

https://a.axihe.com/focus/js/http/http-18-05.png

6、window.opener

适用于IE6、7,也就是operner hack方法,不过貌似现在已经不管用了,只要打过微软的安全补丁.kb2497640就不能用了 

  • a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面 
  • b、发起方页面通过iframe.content Window.opener = {a: function(params){...}, b: function(params){...} ...}来定义可被接收方调用的方法 
  • c、接收方页面通过window.opener.a/window.opener.b来调用发起方定义的方法 
  • d、接收方页面通过parent.opener = {c: function(params){...}, d: function(params){...} ...}来定义可被发起方调用的方法 
  • e、发起方页面通过opener.c/opener.d来调用接收方定义的方法 

其实原理就是重置opener对象

https://a.axihe.com/focus/js/http/http-18-06.png

7、window.navigator

适用于IE6、7,貌似现在还能用,还没被补丁掉 

  • a、发起方页面创建一个隐藏的iframe,并且源指向接收方页面 
  • b、发起方页面通过window.navigator.a = function(params){…}; window.navigator.b = function(params){…}; 来定义被接   收方调用的方法 
  • c、接收方页面通过window.navigator.a(params); window.navigator.b(params);来调用发起方定义的方法 
  • d、接收方页面通过window.navigator.c = function(params){…}; window.navigator.d = function(params){…}; 来定义被发起方调用的方法 
  • e、发起方页面通过window.navigator.c(params); window.navigator.d(params);来调用接收方定义的方法  

https://a.axihe.com/focus/js/http/http-18-07.png

更多面试题

如果你想了解更多的前端面试题,可以查看本站的WEB前端面试题 ,这里基本包涵了市场上的所有前端方面的面试题,也有一些大公司的面试图,可以让你面试更加顺利。

面试题
HTML CSS JavaScript
jQuery Vue.js React
算法 HTTP Babel
BootStrap Electron Gulp
Node.js 前端经验相关 前端综合
Webpack 微信小程序 -

这些题库还在更新中,如果你有不错的面试题库欢迎分享给我,我整理后放上来;人人为我,我为人人,互帮互助,共同提高,祝大家都拿到心仪的Offer!

AXIHE / 精选资源

浏览全部教程

面试题

学习网站

前端培训
自己甄别

前端书籍

关于朱安邦

我叫 朱安邦,阿西河的站长,在杭州。

以前是一名平面设计师,后来开始接接触前端开发,主要研究前端技术中的JS方向。

业余时间我喜欢分享和交流自己的技术,欢迎大家关注我的 Bilibili

关注我: Github / 知乎

于2021年离开前端领域,目前重心放在研究区块链上面了

我叫朱安邦,阿西河的站长

目前在杭州从事区块链周边的开发工作,机械专业,以前从事平面设计工作。

2014年底脱产在老家自学6个月的前端技术,自学期间几乎从未出过家门,最终找到了满意的前端工作。更多>

于2021年离开前端领域,目前从事区块链方面工作了