Front-end Related饥人谷技术博客

跨域的几种实现方式

2017-07-02  本文已影响0人  虚玩玩TT

概念1:同源策略

同源策略,Same-origin policy,浏览器处于安全考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。

概念2:本域

跨域

因为浏览器的同源策略,如果不加特殊处理,在一个页面中向不同域的接口发送请求是不会得到数据的,这种向不同域的接口发送请求的行为就是跨域。

实现跨域

方式

JSONP

原理:

html中的script标签可以引入其他域下的js,利用这个特性可以达到跨域。

通过script.src指定域名发送请求
后端经过处理返回特定的字符串(函数格式)
返回的数据作为参数传入一个数据处理函数
这时执行JS中的数据处理函数就可以实现数据交换,达到跨域的目的。

代码演示:
<!DOCTYPE html>
<html>
<head>
  <meta chartset="utf-8">
  <title>跨域-jsonp</title>
</head>
<body>
  <button>点我</button>
  <ul class="news"></ul>
 
  <script>
    var btn = document.querySelector("button")

    btn.addEvevtListener('click',function(){
      var script = document.createElement('script')
      script.src = 'http://localhost:8080/getNews?callback=appendHtml'
      document.head.appendChild(script)
      document.head.removeChild(script)
    })

    function appendHtml(news){
      var html = ''
      html += '<li>' + news + '</li>'
      var addnews = document.querySelector('.news')
      addnews.innerHTML = html
    }
  </script>
</body>
</html>
-----------------------------------------------
使用mock-server模拟后端

router.get('/getnews',function(req,res){
  var news = ["test1","test2","test3","test4","test5"]
  var data = []

  var index = parseInt(math.random()*news.length)
  data.push(news[index])

  var cb = req.query.callback
  if(cb){
    res.send(cb + '(' + JSON.stringify(data) + ')')  //在后端将返回的数据处理成函数格式返回到JS后执行,达到跨域目的
  }else{ res.send(data)}
  
})
效果
JSONP结果.png

CORS

Cross-Origin Resource Sharing,跨域资源共享,是一种ajax跨域请求资源的方法。

原理

当使用XMLHttpRequest发送请求时,当浏览器发现请求不符合同源策略时,浏览器会给该请求加一个请求头origin,值为当前页面的域名,通过后端处理,返回结果中加入一个响应头Access-Control-Allow-Origin,如果值也为origin或者"*",则可以拿到数据,实现跨域。

代码演示
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>跨域-cors</title>
</head>
<body>
  <button class="btn">点我</button>
  <ul class="news"></ul>

  <script>
    var btn = document.querySelector('.btn')

    btn.addEventListener("click",function(){
      var xhr = new XMLHttpRequest()
      xhr.open('get','http://b.jirengu.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 addnews = ducument.querySelector('.news')
      var html = ''

      html += '<li>' + news + '</li>'
      addnews.innerHTML= html
    }
  </script>
</body>
</html>

-------------------------------------------------------------------------

使用mock-server模拟后端

router.get('/getNews',function(req,res){
  var news = ['test1','test2','test3','test4','test5','test6','test7']
  var data = []
  var index = parseInt(Math.random()*news.length)

  data.push(news[index])

  res.header("Access-Control-Allow-Origin","http://a.jrg.com:8080")
  // res.header("Access-Control-Allow-Origin","*")
  res.send(data)
})
效果
修改host.PNG CORS结果.PNG

降域

对于页面中使用iframe嵌套另外的网站时,如果符合同源策略,就可以通过window.frames[].document操作对应iframe里的网站,如果不符合,则不能相互访问,但是如果这些网站有着相同的主网站,则可以通过降域实现跨域。例如:a.test.com:8080和b.test.com:8080的主域名为test.com:8080

原理

在script标签里写上document.domain = "主域名",就可以实现降域,
然后就可以使用window.frames[].document操作对应iframe里的网站,实现跨域。

代码演示
创建a.html文件

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>跨域-降域-a</title>
</head>
<body>
  <div class="ct">
    <div class="main">
      <input type="text" placeholder="http://a.jirengu.com:8080/a.html">
    </div>
    <iframe src="http://b.jirengu.com:8080/b.html"></iframe>
  </div>
  <script>
    document.querySelector('.main input').addEventListener('input',function(){
      windows.frames[0].document.querySelector('input').value = this.value
    })
    document.domain = "jirengu.com"
  </script>
</body>
</html>

----------------------------------------------------------------

创建b.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>b.html</title>
</head>
<body>
  <input type="text" placeholder="http://b.jirengu.com:8080/b.html">

  <script>
    document.querySelector('input').addEventListener('input',function(){
      windows.parent.document.querySelector('input').value = this.value
    })
    document.domain = "jirengu.com"
  </script>
</body>
</html>
效果

在前面已修改了hosts文件,将测试用的a.jirengu.com和b.jirengu.com写入到hosts中对应127.0.0.1,然后使用server-mock模拟后端。

降域1.PNG 降域2.PNG

postMessage

postMessage()方法允许来自不同源的脚本采用异步方式进行有限的通信,可以实现跨文本档、多窗口、跨域消息传递。

postMessage(data,origin)方法接受两个参数

data:要传递的数据
origin:可以设置目标窗口的url,只包括协议、域名、端口。也可以设置为"*",表示传递给任意窗口

原理

postMessage可向任意窗口发送数据,由目标窗口选择接受数据。

通过postMessage()发送数据,然后再写一个监听函数就可以实现跨域操作。

代码演示
创建a.html文件

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>跨域-降域-a</title>
</head>
<body>
  <div class="ct">
    <div class="main">
      <input type="text" placeholder="http://a.jirengu.com:8080/a.html">
    </div>
    <iframe src="http://b.jirengu.com:8080/b.html"></iframe>
  </div>
  <script>
    var input = document.querySelector('.main input')

    input.addEventListener('input',function(){
      window.frames[0].postMessage(this.value,"*")
    })

    window.addEventListener('message',function(e){
      input.value = e.data
    })
    
  </script>
</body>
</html>

----------------------------------------------------------------

创建b.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>b.html</title>
</head>
<body>
  <input type="text" placeholder="http://b.jirengu.com:8080/b.html">

  <script>
    var input = document.querySelector('input')

    input.addEventListener('input',function(){
      window.parent.postMessage(this.value,'http://a.jirengu.com:8080')
    })

    window.addEventListener('message',function(e){
      input.value = e.data
    })
    
  </script>
</body>
</html>
效果

这个demo演示效果和降域一样。

以上。

上一篇 下一篇

猜你喜欢

热点阅读