跨域

104 阅读3分钟

一 同源策略

  1. 如果两个url的协议,域名,端口号完全一致,那么这两个url就是同源的。
  2. 浏览器规定,如果js运行在源A里,那么就只能获取源A的数据,不能获取源B的数据,即不允许跨域
  3. 浏览器这样设计的目的是保护用户的隐私。
  4. 假如浏览器没有不允许跨域的规定。那么正常请求页面里的js和黑客网页里的js发的请求几乎没有区别(referer有区别),如果后台开发者没有检查referer,那么就完全没区别。所以,如果没有同源策略,任何页面都能偷服务器的数据。虽然检查referer可以避免该问题,但万一没有检查呢?因此浏览器应该主动预防这种偷数据的行为。总之,浏览器为了用户隐私,设置了严格的同源策略。
  5. 同源策略,不同源的页面之间,不准互相访问数据。
  6. 黑客跨域请求时,请求一般发成功了,但是拿不到响应,因为浏览器不给数据给它。

二 为什么可以跨域使用CSS,JS和图片等?

同源策略限制的是数据访问,我们引用CSS,JS和图片的时候,其实 并不知道其内容,我们只是在引用。

三 使用CORS实现跨域

  1. 问题根源
    浏览器默认不同源之间不能互相访问数据,但是源A和源B其实都是自己的网站,此时就想要两个网站互相访问。
  2. 使用CORS(Cross-origin resource sharing)。如果要共享数据,需要提前声明。源B可以在响应头里面标注源A可以访问。Access-Control-Allow-Origin:源A地址。
  3. IE 6789都不支持CORS

四 使用JSONP实现跨域

  1. 在跨域的时候,由于浏览器不支持CORS,必须使用其他的方法跨域。同时,虽然不能跨域获取数据,但是可以跨域引用js呀,让js包含数据就好了。
  2. 源A请求源B的一个js文件,这个js文件会执行一个回调,回调里面就会用到源A想要的源B中数据。
  3. 回调的名字可以是源A随机生成的,源A把这个名字作为callback参数的值传给源B,源B会把这个函数再次返回给源A并执行这个函数。
 //源A想要跨域访问源B
 
   //源A中使用jsonp
   function jsonp(url) {
    return new Promise((resolve, reject) => {
      const random = "specialString" + Math.random();
      window[random] = (data) => {
        resolve(data);
      };
      const script = document.createElement("script");
      script.src = `${url}?callback=${random}`;
      script.onload = () => {
        //下载完引用的js后,删除script标签,否则页面会变臃肿
        script.remove();
      };
      script.onerror = () => {
        reject();
      };
      document.body.appendChild(script);
    });
  }

  jsonp("源B的url").then((data) => {
    console.log(data);
  },(err)=>{
    console.log(err);
  });
  
  //源B中服务器中相应的处理代码
  if (path === "/xxx") {
    if (request.headers["referer"].indexOf("源A的url") === 0) {
      response.statusCode = 200;
      response.setHeader("Content-Type", "text/javascript;charset=utf-8");
      const string = `window['{{xxx}}']({{data}}) `;
      const data = fs.readFileSync("源B服务器上存放数据的路径").toString();
      const string2 = string
        .replace("{{data}}", data)
        .replace("{{xxx}}", query.callback);
      response.write(string2);
      response.end();
    } else {
      response.statusCode = 404;
      response.end();
    }
  }

  1. 优点:兼容IE;可以跨域。
  2. 缺点:由于是script标签,因此读不到ajax那么精确地状态,不知道状态码是什么,也不知道整个响应的头是什么,只知道成功或失败;由于它是script标签,所以只能发get请求,不支持post;谁都可以访问js文件,因此必须做referer检查。