Javascript跨域问题总结

8 篇文章 0 订阅
3 篇文章 0 订阅

    今天来总结下前端跨域问题的解决方案,网上有很多这个问题的总结和描述了;跨域问题也是前端的一个老问题了,现在就来简单聊聊。

     同源策略(Same origin policy)是一种约定,它是浏览器最核心也最基本的安全功能,如果缺少了同源策略,则浏览器的正常功能可能都会受到影响,它要求请求的协议,端口,域名一致。如果请求的协议,端口,域名任何一个不一样,则出现跨域问题。同源策略的限制有2个:

 

  • 不能通过ajax的方法去请求不同源中的文档
  • 不同域的iframe之间不能进行js交互操作

前端跨域问题时常出现,目前有以下7中常用的跨域解决方案:

1、JSONP

     大家耳熟能详的一个解决跨域问题的方式是使用JSONP,实现的原理是:<script>标签可以加载跨域的javascript脚本,并且被加载的脚本和当前文档属于同一个域。

     JSONP方式由2部分组成:回调函数数据callback回调函数是接受response响应在页面中调用的函数,而数据就是传入回调函数中的JSON数据。

    同时服务器端需要进行相应的处理,即请求的callback回调函数,并将运算产生的数据为参数调用callback函数。

1. 前端向服务器发送请求,并带上callback回调函数

<script type="text/javascript">
    function dosomething(jsondata){
        //处理获得的json数据
    }
</script>
<script src="http://example.com/data.php?callback=dosomething"></script>

   2.  后端接受请求获取callback

<?php
$callback = $_GET['callback'];//得到回调函数名
$data = array('a','b','c');//要返回的数据
echo $callback.'('.json_encode($data).')';//输出
?>

    如果项目中使用的jquery,jquery会自动生成一个全局函数来替换callback=?中的问号

<script type="text/javascript">
    $.getJSON('http://example.com/data.php?callback=?,function(jsondata)'){
        //处理获得的json数据
    });
</script>

    $.getJSON方法会自动判断是否跨域,不跨域就调用普通的ajax方法;跨域则会以异步加载js文件的形式来调用jsonp的回调函数。

 

2、iframe+domain

    通过设置document.domain共享cookie这种方式主要是用来跨子域。domain的设置有一定的限制,只能将domian设置成自身或更高一级的父域,且主域相同。

try {
  requestByFrame();
} catch (e) {
  document.domain = (location.host.match(/[^.]+\.[^.]+$/)[0]).replace(/:\d+/, "");
  //跨域
  var iframe = document.createElement("iframe");
  iframe.id = iframe.name = "proxyFrame";
  iframe.style.display = "none";

  var proxyUrl = location.protocol + "//" + main.domain + "/proxy.html?rnd=" + Math.random();
  iframe.src = proxyUrl;
  document.body.appendChild(iframe);
  iframe.onload = function() {
    requestByFrame();
  }
}

function requestByFrame() {
  var win = frames["proxyFrame"];
  if (win.location.host === top.location.host) {
    throw "error";
  } else {
    conf.xhr = new win.XMLHttpRequest;
    ajax(conf);
    //...
  }
}

 

3、postMessage

    html5中新增了window.postMessage(message,targetOrigin) 方法,可以使用它来向其它的window对象发送消息。无论这个window对象是属于同源或不同源,目前IE8+、FireFox、Chrome、Opera等浏览器都已经支持。

    postMessage(message,targetOrigin)接受2个参数,第一个参数message是是消息体,支持字符串和对象;第二个参数目标域名,可设置成*,表示所有的域都可以接受消息;

window.parent.postMessage({
    act:'response',
    msg:{
       answer:url
    }
},'a.cn');

在目标域a.cn中接收postMessage发送过来的消息体

//a.cn中监听第三方postMessage发送过来的消息
window.addEventListener('message', function(e){
  if (e.data.act == 'response' && e.origin.indexOf("a.cn") > -1) {
      var answer = e.data.msg.answer;
      if(answer.indexOf("http://") > -1 || answer.indexOf("https://") > -1){
         alert(e.data.msg.answer);
      }
      
  } else {
      console.log('未定义的消息: '+ e.data.act);
  }
}, false);

 

4、CORS

 

    CORS(Cross-origin resource sharing)跨域资源共享适用于通过XMLHttpRequest / XDomainRequest请求接口的情形,其思想是使用自定义的HTTP头部让浏览器与服务器进行沟通,从而决定请求或响应是应该成功,还是应该失败。

    实现CORS跨域,需要服务器进行配置,主要是三点:允许跨域的域名(Access-Control-Allow-Origin),允许请求的方法(Access-Control-Allow-Methods),允许请求的方式(Access-Control-Allow-Headers)。

CORS 和 JSONP的区别:
    1.JSONP只支持GET方式,CORS支持所有的HTTP请求;
    2.CORS可以像普通的XMLHttpRequest发起请求和获得数据;
    3.JSONP主要被老的浏览器支持,它们往往不支持CORS,而绝大多数现代浏览器都已经支持了CORS);

详细介绍可参看CORS详解

 

5、nginx反向代理

    利用nginx反向代理来实现跨域请求是目前大部分公司采用的方式。

    

在nginx中增加location反向代理到服务器端设置:

server {
    listen       80;
    server_name  serverName; 
    location /m/ {
        proxy_pass http://example/xxx/api; //将/m/的请求转发example上
    }
}

6、WebSocket

    利用WebSocket可以进行跨域访问的原因是因为WebSocket使用ws://(非加密)和wss://(加密)作为协议,该协议不实行同源政策,所以可以进行跨域请求。

 

7、window.name

 

     window对象有个name属性,在一个窗口(window)的生命周期内,窗口载入的所有的页面都是共享一个window.name的,每个页面对window.name都有读写的权限,window.name是持久存在一个窗口载入过的所有页面中的,window.name大小2M左右。

    实现:a.html跨域请求不同域中的data.html内的window.name数据,在a.html 新建一个隐藏的proxy的iframe  ,iframe.src ='xxx/b.html',设置iframe的的onload方法,在onload function中获取b.html中的window.name值,再设置iframe的src为与a.html同源的b.html或者为about:blank。

    例如:在index中,创建一个index2.设置对应的window.name.然后修改href到对应的iframe页面.处理完成后由iframe修改href返回到index域下的某个页面,读取window.name。

 

跨域总结完成,如有纰漏欢迎指正~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值