JSONP,跨域

JSONP、跨域是面试必问问题之一
困难在于脑海里认为一个ajax请求的结果是一个json或XML
如果不用ajax请求

json内容不是固定的,传什么给什么

}else if(path === '/main.js'){  
    var string = fs.readFileSync('./main.js', 'utf8')
    response.setHeader('Content-Type', 'application/javascript')
    response.end(string.replace('%xxx%', query.content))
  }else{

jsonp = json+padding
发一个请求,服务器根据请求参数返回js,js插入页面,被执行

如果js所在的源与要请求的源不一样,浏览器会拒绝把响应给js

CORS

只要JS请求的源在响应里加上
:<JS所在的源>

状态码
2xx 一切安好
3xx 滚 301:滚到另外一个地址上去 302:
4xx 你错了
5xx 我错了
200 ok
204 新建成功

403:没有权限访问
404:没有找到

 btn.onclick = function(){
    var number = parseInt(Math.random() * 10000000,10)
    var functionName = 'jQuery'+ number

    window[functionName] = function(data){
      console.log(data)
    }

    var script = document.createElement('script')
    var value = document.querySelector('#xxx').value
    script.src = '/main.js?content=' + functionName 
    document.body.appendChild(script)
  }
 btn.onclick = function(){
    jsonp('/main.js', 'content')
  }

  function jsonp(url, param){
    var number = parseInt(Math.random() * 10000000,10)
    var functionName = 'jQuery'+ number

    window[functionName] = function(data){
      console.log(data)
    }

    var script = document.createElement('script')
    var value = document.querySelector('#xxx').value
    script.src = url + '?'+ param + '=' + functionName 
    document.body.appendChild(script)
  }

题目1: 什么是同源策略
浏览器出于安全方面的考虑,只允许与本域下的接口交互。不同源的客户端脚本在没有明确授权的情况下,不能读写对方的资源。本域指的是同协议,同域名,同端口。

题目2: 什么是跨域?跨域有几种实现形式。
1.JSONP
例如我要从域A的页面pageA加载域B的数据,那么在域B的页面pageB中我以JavaScript的形式声明pageA需要的数据,然后在 pageA中用script标签把pageB加载进来,那么pageB中的脚本就会得以执行。

function getData(data){
    //这里是对获取的数据的相关操作
    console.log(data);
    //数据获取到后移除创建的script标签
    document.body.removeChild(originData);
}
var originData = document.createElement('script');
originData.src = 'http://www.jesse.com/data.js';
originData.setAttribute("type", "text/javascript");
document.body.appendChild(originData);

2.CORS
跨源资源共享(CORS)定义一种跨域访问的机制,可以让AJAX实现跨域访问。CORS允许一个域上的网络应用向另一个域提交跨域AJAX请求。实现此功能非常简单,只需由服务器发送一个响应标头即可。它只要JS请求的源在响应里加上Access-Control-Allow-Origin:<JS所在的源>。

3.降域
对于主域相同而子域不同的例子,可以通过设置document.domain的办法来解决。 具体的做法是可以在http://www.a.com/a.htmlhttp://script.a.com/b.html两个文件中分别加上 document.domain = "a.com";然后通过a.html文件中创建一个iframe,去控制iframe的contentDocument,这样两个js文件之间就可以 “交互”了。

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

JSONP是针对接口的,CORS是针对域名的有可能会遭到XSS攻击,CORS在IE8上的兼容性不好,偶尔调用的话就可以选JSONP

题目3: JSONP 的原理是什么?
1.页面上调用js文件时不受跨域的影响,而且,凡是拥有src属性的标签都拥有跨域的能力,比如<script>、<img>、<iframe>。
2.可以在远程服务器上设法把数据装进js格式的文件里,供客户端调用处理,实现跨域。
3.目前最常用的数据交换方式是JSON,客户端通过调用远程服务器上动态生成的js格式文件(一般以JSON后缀)。
4.客户端成功调用JSON文件后,对其进行处理。
5.为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

题目4: CORS是什么?
CORS 全称是跨域资源共享(Cross-Origin Resource Sharing),是一种 ajax 跨域请求资源的方式,支持现代浏览器,IE支持10以上。 实现方式很简单,当你使用 XMLHttpRequest 发送请求时,浏览器发现该请求不符合同源策略,会给该请求加一个请求头:Origin,后台进行一系列处理,如果确定接受请求则在返回结果中加入一个响应头:Access-Control-Allow-Origin; 浏览器判断该相应头中是否包含 Origin 的值,如果有则浏览器会处理响应,我们就可以拿到响应数据,如果不包含浏览器直接驳回,这时我们无法拿到响应数据。
简单请求
某些请求不会触发 CORS 预检请求,本文称这样的请求为“简单请求”,请注意,该术语并不属于 Fetch (其中定义了 CORS)规范。若请求满足所有下述条件,则该请求可视为“简单请求”:
使用下列方法之一:GET , HEAD , POST
预检请求
与前述简单请求不同,“需预检的请求”要求必须首先使用 OPTIONS方法发起一个预检请求到服务器,以获知服务器是否允许该实际请求。"预检请求“的使用,可以避免跨域请求对服务器的用户数据产生未预期的影响。

题目5: 根据视频里的讲解演示三种以上跨域的解决方式。
JSONP:
index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <div class="container">
      <ul class="news">
        <li>第11日前瞻:中国冲击4金 博尔特再战</li>
        <li>男双力争会师决赛 </li> 
        <li>女排将死磕巴西!</li>
      </ul>
      <button class="change">换一组</button>
  </div>
  <script>
    $('.change').addEventListener('click', function(){
      var script = document.createElement('script');
      script.src = 'http://b.jrg.com: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>';
      }
      $('.news').innerHTML = html;
    }
    
    function $(id){
      return document.querySelector(id);
    }
  </script>  
</body>
</html>

router.js

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);
    }
    
})

CORS
index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
</head>
<body>
  <div class="container">
      <ul class="news">
        <li>第11日前瞻:中国冲击4金 博尔特再战</li>
        <li>男双力争会师决赛 </li> 
        <li>女排将死磕巴西!</li>
      </ul>
      <button class="change">换一组</button>
  </div>
  <script>
    $('.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.readyState === 200){
                appendHtml(JSON.parse(xhr.responseText))
            }
        }
    })
    
    function appendHtml(news){
      var html = '';
      for( var i=0; i<news.length; i++){
        html += '<li>' + news[i] + '</li>';
      }
      $('.news').innerHTML = html;
    }
    
    function $(id){
      return document.querySelector(id);
    }
  </script>  
</body>
</html>

router.js

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.send(data);
})

postMessage
a.html

<!DOCTYPE html>
<html>
<head>  
    <meta charset="utf-8">
    <style>
    .ct{
      width: 910px;
      margin: auto;
    }
    .main{
      float: left;
      width: 450px;
      height: 300px;
      border: 1px solid #ccc;
    }
    .main input{
      margin: 20px;
      width: 200px;
    }
    .iframe{
      float: right;
    }
    iframe{
      width: 450px;
      height: 300px;
      border: 1px dashed #ccc;
    }
  </style>
</head>
<body>
    <div class="ct">
        <h1>postMessage</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>
    
    <script>
        $('.main input').addEventListener('input', function(){
        console.log(this.value);
        window.frames[0].postMessage(this.value,'*');
        })
        window.addEventListener('message',function(e) {
                $('.main input').value = e.data
            console.log(e.data);
        });
        function $(id){
            return document.querySelector(id);
        }
    </script>
</body>
</html>

b.html

<!DOCTYPE html>
<html>
<head>  
    <meta charset="utf-8">
    <style>
        html,body{
            margin: 0;
        }
        input{
            margin: 20px;
            width: 200px;
        }
    </style>
</head>
<body>
    <input id="input" type="text"  placeholder="http://b.jrg.com:8080/b.html">
    
    <script>
        $('#input').addEventListener('input', function(){
            window.parent.postMessage(this.value, '*');
        })
        window.addEventListener('message',function(e) {
            $('#input').value = e.data
            console.log(e.data);
        });
        function $(id){
            return document.querySelector(id);
        }
    </script>
</body>
</html>

推荐阅读更多精彩内容