网络之巧妙的JSONP跨域

1. 什么是同源策略?

同源策略是浏览器的一种安全策略。
同源策略阻止从一个源加载的文档或脚本获取或设置另一个源加载的文档的属性
当浏览器的tab页执行一个脚本的时候会检查这个脚本是属于哪个页面的,
如果非同源,那么在请求数据时,浏览器会在控制台中报一个异常,提示拒绝访问。
协议、域名、端口均相同的源才属于同源。

我们来进行一个练习,你就会知道什么是同源策略了,练习如下:
以下哪些与http://vip.chanke.xyz/chanke/index.html同源? (注意:在这里端口号没有写,http默认的端口号是80,https默认的端口号是443。

http://www.chanke.xyz/chanke/index.html 不是同源,因为域名不同(注意:域名只要长得不一样就是不相同,哪怕一个字母不相同也是不相同,差一个点也是不相同;只有长得一模一样的才算相同。)

http://vip.chanke.xyz:81/chanke/index.html 不是同源,因为端口不同(上面是80端口,而这里是81端口,所以端口号是不相同的。)

https://vip.chanke.xyz/chanke/index.html 不是同源,因为协议不同(上面是http协议,而这里是https协议,所以协议是不相同的)

http://vip.chanke.xyz/aimee/index.html 同源(协议都是http协议,域名都是vip.chanke.xyz,端口都是默认的80端口,因此是同源的。)

2. JSONP的诞生

  1. 首先,因为ajax无法跨域,然后开发者就有所思考;
  2. 其次,开发者发现, 标签的src属性是可以跨域的;
  3. json刚好被js支持(object);
  4. 调用跨域服务器上动态生成的js格式文件(不管是什么类型的地址,最终生成的返回值都是一段js代码);
  5. 这种获取远程数据的方式看起来非常像ajax,但其实并不一样。便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP;
  6. 传递一个callback参数给跨域服务端,然后跨域服务端返回数据时会将这个callback参数作为函数名来包裹住json数据即可。

3. JSON和JSONP完全是两码事

JSON是一种数据交换格式,而JSONP是一种依靠开发人员的聪明才智创造出的一种非官方跨域数据交互协议。

4. JSONP与AJAX的区别是什么

  1. ajax和jsonp本质上是不同的东西;
  2. ajax的核心是通过XmlHttpRequest获取非本页内容;
  3. jsonp的核心则是动态添加标签来调用服务器提供的js脚本。

5. src和iframe可以访问到不同源的地址吗?

思考一个问题,下面这些能访问到吗?

1
2
3
<img src="https://www.baidu.com/img/bd_logo1.png?qua=high&where=super" alt="">
<iframe src="https://www.baidu.com/" frameborder="0"></iframe>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>

答案是肯定可以访问到的。其原因是因为src不受同源策略限制

6. 你向这个接口发送请求的时候,你的数据是如何交互的?(面试重点)

http://vip.chanke.xyz/git/chanke/demo.txt 链接中的内容形式为:cbs({“name”: “aimee”,”age”: 18})
此时你会发现它是一个函数执行的形式,然后括号里面传入的是实参。

1
2
3
4
5
6
7
8
9
10
11
12
<button class="btn">btn</button>
<script>
var oBtn = document.getElementsByClassName("btn")[0];
oBtn.onclick = function(){
var oScript = document.createElement("script");
oScript.src = "http://vip.chanke.xyz/git/chanke/demo.txt";
document.body.appendChild(oScript);
};
function cbs(data){
console.log(data); //{name: "aimee", age: 18}
}
</script>

注意:如果一个数据单独长成JSON格式的话(如:demo.txt文件中的内容为{“name”:”aimee”,”age”:18}),你获取不到。此时我们解决它的办法就是:将数据放到函数中做处理,如demo.txt文件中改为:cbs({“name”:”aimee”,”age”:18})。但是此时cbs函数名是后端自己取的,我们不知道后端给我们传过来叫什么名字,我们的解决办法就是将‘oScript.src = “http://vip.chanke.xyz/git/chanke/demo.txt";’ 中写好的函数名告诉给前端,是通过传参的形式来告诉的,如:oScript.src = “http://vip.chanke.xyz/git/chanke/demo.txt?cb=cbs"; 一般像cb这一类的,在接口文档中都会告诉你的。

面试重点:你向这个接口发送请求的时候,你的数据是如何交互的?
答:就是将回调函数的名称给后台传送过去,然后后台会将你的函数名称拼接好,返回一个:回调函数名(…)执行的形式。然后当你拿到数据后,这个回调函数就可以执行了。