30分钟学会最实用的前端跨域解决方案

290 阅读3分钟

【前言】

面试官:“请问你遇到过跨域吗?最后是怎么解决的呢?”

我:“。。。。”

作为前端面试出现频率最高的面试题,跨域确实很能区分出是否有实战经验,因为这个问题没有实操过代码,想表达清楚,确实不易。接下来就让我们用最简单的实战来学会它吧。文末附有完整代码链接。

【目录】

  1. 同源策略
  2. 什么是跨域
  3. CORS
  4. jsonp

【正文】

1. 同源策略

同源即:同一协议,同一域名,同一端口号

举例

http://qq.com  http://baidu.com   \\不同源
http://www.baidu.com     http://baidu.com       \\不同源
\\完全一致才同源

同源策略:浏览器规定,如果JS运行在源A,那么就只能获取源A的数据,不能获取源B的数据,即不允许跨域

举例

假设Russ.com/index.html cdn.com/1.js
那么就说[1.js运行在源Russ.com里]
注意这和cdn.com没有关系,虽然1.js从它那下载,所以1.js就只能获取Russ.com的数据
不能获取1.russ.com或者qq.com的数据

这是浏览器故意设计的一个功能限制, 目的是为了保护用户隐私

如果没有同源策略,以QQ空间为例

假设当前用户已经登录,AJAX请求/fridens.json可获取用户好友列表,到目前为止全部安全

现在黑客可以给你一个钓鱼网站,只要你点开这个网页,这个网页也请求你的好友列表,请问你的好友列表是不是就把黑客偷偷走了,但并没有,这时候浏览器的同源策略就发挥作用了。

举例

1.创建qq-com,里面有一个server.js
2./index.html为首页
3./qq.js是JS脚本
4./fridends.json是模拟好友数据
4.端口监听888
1.创建Russ-com,里面有一个server.js
2./index.html为首页
3./Russ.js是JS脚本
4.端口监听9999
//Russ.js请求代码
function ajax(method, url) {
  return new Promise((resolve, reject) => {
    const request = new XMLHttpRequest();
    request.open(method, url);
    request.onreadystatechange = () => {
      if (request.readyState === 4) {
        if (request.status === 200) {
          resolve(request.response);
        } else {
          reject(request);
        }
      }
    };
    request.send();
  });
}
ajax("get", "http://localhost:8888/friends.json").then((response) => {
  console.log("这是 AJAX");
  console.log(response);
});

黑客网站

QQ空间

这就是同源策略,如果没有同源策略浏览器就是bug,双马早就破产了

2.什么是跨域?

跨域,是指浏览器不能执行其他网站的脚本(跨站请求可能可以正常发起,但是返回结果被浏览器拦截了)。它是由浏览器的同源策略造成的,是浏览器对JavaScript实施的安全限制。

虽然同源策略很安全,但在其他源默认的前提下,我们是有需求去获取其他源的数据的。这时候我们就要祭出我们的前端跨域方案了。

3.方案一CORS

浏览器说,如果要获得对方数据,必须获得对方的同意

于是,qq.com在响应头里写Russ.com(http://localhost:9990)可以访问

这时候黑客网站就可以访问好友列表了

这就是CORS,是不是特别简单。

但这时候IE又出现了,说我不支持!!!

于是jsonp出现了

4.方案二JSONP

有没有发现js居然可以跨域引用,这是因为src在发挥作用。

于是当我们在跨域时,因为当前浏览器不支持CORS(或其他原因),于是我们请求一个JS文件,这个JS文件会执行一个回调,回调里面就有我们的数据。回调名字可以是一个随机生成的随机数,然后已url?callback的方式的方式传给后台,后台会将函数再次返回给我们并执行。

是不是有点晕

让我们来举例把

举例

Russ.com访问qq.com
qq.com将数据写到/friends.js
对引用/friends.js做限制
request.headers["referer"].indexOf("http://localhost:9990") === 0)
Russ.com用script标签引用/friends.js
/friends.js执行,执行什么呢
Russ.com事先定义好window.xxx函数(回调函数)
/friends.js执行window.xxx(data)
Russ.com就通过windox.xxx获取到数据

这时候黑客就能通过jsonp就可以愉快的获取好友列表了

文中所有代码链接:github.com/RussellWest…

创作总结不易,如有错误,感谢指正。