跨域

什么是同源策略

同源策略(same origin policy),1995年同源政策由 Netscape 公司引入浏览器。目前,所有浏览器都实行这个政策浏览器出于安全方面的考虑,只允许与本域下的接口进行交互。不同源的客户脚本在没有明确授权的情况下,不能读取对方的资源。
同源政策的目的,是为了保证用户信息的安全,防止恶意的网站窃取数据

本域指的是

  • 同协议:比如都是 http 或者 https
  • 同端口:比如都是 80 端口
  • 同域名:比如都是 google.com

什么是跨域?跨域有几种实现形式

跨域是指通过一定方式绕过浏览器同源政策的限制,可以与不同域进行交互
目前学习到四种实现形式:

  • JSONP
  • CORS
  • 降域
  • postMessage

JSONP 的原理是什么

jsonp 是一种跨域通信的手段,它的原理其实很简单:

  1. 首先是利用 script 标签的 src 属性来实现跨域。
  2. 通过将前端方法作为参数传递到服务器端,然后由服务器端注入参数之后再返回,实现服务器端向客户端通信。
  3. 由于使用 script 标签的 src 属性,因此只支持 get 方法

CORS是什么

  • CORS 是一个 W3C 标准,全称是“跨域资源共享”(Cross-origin resource sharing,它允许浏览器向跨源服务器,发出 XMLHttpRequest 请求,从而克服了 AJAX 只能同源使用的限制

  • CORS 需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于 IE10。

  • 整个 CORS 通信过程,都是浏览器自动完成,不需要用户参与。对于开发者来说,CORS 通信与同源的 AJAX 通信没有差别,代码完全一样。浏览器一旦发现 AJAX 请求跨源,就会自动添加一些附加的头信息,有时还会多出一次附加的请求,但用户不会有感觉。

因此,实现 CORS 通信的关键是服务器。只要服务器实现了 CORS 接口,就可以跨源通信。

参考阮一峰

根据视频里的讲解演示三种以上跨域的解决方式 ,写成博客

  • JSONP
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')

http.createServer(function(req, res){
  var pathObj = url.parse(req.url, true)

  switch (pathObj.pathname) {
    case '/getNews':
      var news = [
        "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
        "正直播柴飚/洪炜出战 男双力争会师决赛",
        "女排将死磕巴西!郎平安排男陪练模仿对方核心"
        ]
      res.setHeader('Content-Type','text/json; charset=utf-8')
      if(pathObj.query.callback){
        res.end(pathObj.query.callback + '(' + JSON.stringify(news) + ')')  // 将数据处理后返回
      }else{
        res.end(JSON.stringify(news))
      }

      break;

    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, 'not found')
          res.end('<h1>404 Not Found</h1>')
        }else{
          res.end(data)
        }
      }) 
  }
}).listen(8080)
<!DOCTYPE html>
<html>
<body>
  <div class="container">
    <ul class="news">
    </ul>
    <button class="show">show news</button>
  </div>

<script>
   // 通过script标签发送请求
  $('.show').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;
  }

  function $(id){
    return document.querySelector(id);
  }
</script>

</html>
  • CORS
var http = require('http')
var fs = require('fs')
var path = require('path')
var url = require('url')

http.createServer(function(req, res){
  var pathObj = url.parse(req.url, true)

  switch (pathObj.pathname) {
    case '/getNews':
      var news = [
        "第11日前瞻:中国冲击4金 博尔特再战200米羽球",
        "正直播柴飚/洪炜出战 男双力争会师决赛",
        "女排将死磕巴西!郎平安排男陪练模仿对方核心"
        ]
      res.setHeader('Access-Control-Allow-Origin','*') // 设置响应头中的属性,允许所有的站点访问
      res.end(JSON.stringify(news))

      break;

    default:
      fs.readFile(path.join(__dirname, pathObj.pathname), function(e, data){
        if(e){
          res.writeHead(404, 'not found')
          res.end('<h1>404 Not Found</h1>')
        }else{
          res.end(data)
        }
      }) 
  }
}).listen(8080)
<!DOCTYPE html>
<html>
<body>
  <div class="container">
    <ul class="news">
    </ul>
    <button class="show">show news</button>
  </div>

<script>

  $('.show').addEventListener('click', function(){
    xhr = new XMLHttpRequest();  // 创建 AJAX 请求
    xhr.open('GET','http://127.0.0.1:8080/getNews',true);
    xhr.send();
    xhr.onload = function(){
      appendHtml(JSON.parse(xhr.responseText));
    }
  })

  function appendHtml(news){
    var html = '';
    for( var i=0; i<news.length; i++){
      html += '<li>' + news[i] + '</li>';
    }
    console.log(html);
    $('.news').innerHTML = html;
  }

  function $(id){
    return document.querySelector(id);
  }
</script>

</html>
  • postMessage
    postMessage 是 HTML5 新增加的一项功能,跨文档消息传输(Cross Document Messaging),目前:Chrome 2.0+、Internet Explorer 8.0+, Firefox 3.0+, Opera 9.6+, 和 Safari 4.0+ 都支持这项功能,使用起来也特别简单
    • 首先创建 a.html

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>postMessage</title>
      </head>
      <body>
        <iframe src="http://localhost:8080/b.html" ></iframe>
        <script>
          window.onload = function(){
            var targetOrigin = "http://localhost:8080";
            window.frames[0].postMessage('看到我发给你的信息没', targetOrigin);
          }
          window.addEventListener('message',function(e){
            console.log('a.html接收到信息:',e.data);
          });
        </script>
      </body>
      </html>
      
    • 创建 b.html

      <!DOCTYPE html>
      <html>
      <head>
        <meta charset="UTF-8">
        <title>postMessageB</title>
      </head>
      <body>
        
        <script>
          window.addEventListener('message',function(e){
            if(e.source != window.parent){
              return
            }
            var data = e.data;
            console.log("b.html接收到的消息", data);
            parent.postMessage("我看到你发的消息了", e.origin)
          })
        </script>
      </body>
      </html>
      

在浏览器中打开 http://localhos/a.html

postMessage.png

跨域成功
参考:MDN

推荐阅读更多精彩内容

  • 什么是跨域?跨域是指一个域下的文档或脚本试图去请求另一个域下的资源,这里跨域是广义的。广义的跨域:1.) 资源跳转...
    LeiLv阅读 8,485评论 1 106
  • 题目1.什么是同源策略? 同源策略(Same origin Policy): 浏览器出于安全方面的考虑,只允许与本...
    FLYSASA阅读 903评论 0 6
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    w_zhuan阅读 111评论 0 0
  • 1. 什么是跨域? 跨域一词从字面意思看,就是跨域名嘛,但实际上跨域的范围绝对不止那么狭隘。具体概念如下:只要协议...
    他在发呆阅读 482评论 0 0
  • 给大家推荐这首歌。 大部分的原因是, 送给所有在清明节不能回家的朋友。 歌词 夜色茫茫 罩四周 天边新月如钩 回忆...
    大胡子猪阅读 82评论 0 2