各种跨域实现

JSONP实现跨域

  • 原理: 网页通过添加一个<script>元素,向服务器请求JSON数据,这种做法不受同源政策限制;服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。
  • 具体实现方式:
    1. 定义数据处理函数fun
    2. 创建script标签,src的地址执行后端接口,最后加个参数callback=fun
    3. 服务端在收到请求后,解析参数,计算返还数据,输出 fun(data) 字符串。
    4. fun(data)会放到script标签做为js执行。此时会调用fun函数,将data做为参数。
前端代码   

此例是从http://localhost:8080发出请求,向http://127.0.0.1:8080请求数据,域名不同,明显属于跨域

$('.change').addEventListener('click', function(){
    var script = document.createElement('script');
    script.src = 'http://127.0.0.1:8080/getNews?callback=appendHtml';
    document.head.appendChild(script);
    document.head.removeChild(script);
  })
  function appendHtml(news){
    var html = '';
    for( var i=0; i<news.length; i++){
      html += '<li>' + news[i] + '</li>';
    }
    console.log(html);
    $('.news').innerHTML = html;
  }

后端代码

app.get('/getNews', function(req, res){

  var news = [
    "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
    "正直播柴飚/洪炜出战 男双力争会师决赛",
    "女排将死磕巴西!郎平安排男陪练模仿对方核心",
    "没有中国选手和巨星的110米栏 我们还看吗?",
    "中英上演奥运金牌大战",
    "博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
    "最“出柜”奥运?同性之爱闪耀里约",
    "下跪拜谢与洪荒之力一样 都是真情流露"
  ]
  var data = [];
  for(var i=0; i<3; i++){
    var index = parseInt(Math.random()*news.length);
    data.push(news[index]);
    news.splice(index, 1);
  }


  var cb = req.query.callback;   // 获取回调函数
  if(cb){
    res.send(cb + '('+ JSON.stringify(data) + ')'); // 组成函数调用时形式的字符串
  }else{
    res.send(data);
  }
})

JSONP只能用get请求来实现,JSONP的优势在于支持老式浏览器

2.cors实现跨域

CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 ajax 跨域请求资源的方式,支持现代浏览器,IE支持10以上。 实现方式很简单,当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
具体实现方式:

  1. 当使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理
  2. 如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin
  3. 浏览器判断该相应头中是否包含 Origin 的值,包含则处理响应,我们成功拿到返回的数据。不包含则由于同源策略的限制,无视响应,我们无法拿到数据
前端代码

此例是从a.jrg.com发送ajax请求,向b.jrg.com请求数据

 $('.change').addEventListener('click', function(){
    var xhr = new XMLHttpRequest();
    xhr.open('get', 'http://b.jrg.com:8080/getNews', true);
    xhr.send();
    xhr.onreadystatechange = function(){
      if(xhr.readyState === 4 && xhr.status === 200){
        appendHtml( JSON.parse(xhr.responseText) )
      }
    }
    window.xhr = xhr
  })
  function appendHtml(news){
    var html = '';
    for( var i=0; i<news.length; i++){
      html += '<li>' + news[i] + '</li>';
    }
    console.log(html);
    $('.news').innerHTML = html;
  }
后台代码

app.get('/getNews', function(req, res){

  var news = [
    "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
    "正直播柴飚/洪炜出战 男双力争会师决赛",
    "女排将死磕巴西!郎平安排男陪练模仿对方核心",
    "没有中国选手和巨星的110米栏 我们还看吗?",
    "中英上演奥运金牌大战",
    "博彩赔率挺中国夺回第二纽约时报:中国因对手服禁药而丢失的奖牌最多",
    "最“出柜”奥运?同性之爱闪耀里约",
    "下跪拜谢与洪荒之力一样 都是真情流露"
  ]
  var data = [];
  for(var i=0; i<3; i++){
    var index = parseInt(Math.random()*news.length);
    data.push(news[index]);
    news.splice(index, 1);
  }
  res.header("Access-Control-Allow-Origin", "http://a.jrg.com:8080"); //在响应的头部添加允许其请求的地址,浏览器在接受到响应后,两者的地址比较,相同则返回响应数据,跨域成功。不同则拦截返回的数据(就是不给你看)。
  //res.header("Access-Control-Allow-Origin", "*");    //*代表所有地址都是可行的
  res.send(data);
})

CORS支持所有类型的HTTP请求,但是只有现代浏览器和ie10以上的浏览器支持。

postMessage实现跨域

postMessage()是HTML5的一个API,使用这种方法最重要的就是发送消息和接受消息。在页面A中向页面B发送请求,然后在页面B中监听请求并获取A发送的数据,即可实现跨域。

页面A发送消息:调用postMessage API向目标窗口B 发送消息
window.postMessage(data, origin)
页面B接收消息:目标窗口B监听message事件
window.addEventListener('message',function (e) { console.log(e.origin,e.data) })
请看具体例子

页面a   a.jrg.com/a.html  像localhost:8080/b.html发送信息

<div class="ct">
  <h1>使用postMessage实现跨域</h1>
  <div class="main">
    <input type="text" placeholder="http://a.jrg.com:8080/a.html">
  </div>

  <iframe src="http://localhost:8080/b.html" frameborder="0" ></iframe>

</div>
<script>
//URL: http://a.jrg.com:8080/a.html
$('.main input').addEventListener('input', function(){
  window.frames[0].postMessage(this.value,'http://localhost:8080/b.html');   // 向http://localhost:8080/b.html发送信息
})
window.addEventListener('message',function(e) {   //监听message事件,接收信息并输入
    $('#input').value = e.data
});
postMessage跨域.png

4. 降域

此种方法需要主域相同且子域不同,有较大限制

页面a
<div class="ct">
  <h1>使用降域实现跨域</h1>
  <div class="main">
    <input type="text" placeholder="http://a.jrg.com:8080/a.html">
  </div>

  <iframe src="http://b.jrg.com:8080/b.html" frameborder="0" ></iframe>

</div>

document.querySelector('.main input').addEventListener('input', function(){
  console.log(this.value);
  window.frames[0].document.querySelector('input').value = this.value;
})
document.domain = "jrg.com"
页面b

document.domain = 'jrg.com';   把两个页面的domain设置成一样即可
降域.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 什么是同源策略 浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能...
    ezrealor阅读 519评论 0 1
  • 什么是同源策略 同源政策(same-origin policy)是指同域名(或ip),同端口,同协议视为同一个域,...
    小囧兔阅读 594评论 0 1
  • 什么是同源策略? 同源策略是指,浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授...
    upup_dayday阅读 274评论 0 0
  • 跨域问题的场景和解决方案多种多样,只要是做前端开发,总会遇到。而且面试时也是必问的问题。所以自己学习总结记录一下。...
    花开_陈凤娟阅读 745评论 0 0
  • 我想在这个没有熟悉的人的地方。表达最真实的情感。 今天的心情有点down有点丧。 希望自己能过得没心没肺一些,能任...
    卡卡茶味阅读 209评论 0 0