JS跨域及解决方案

717 阅读4分钟

跨域问题的产生

跨域是指从一个源的网页去请求另一个源的网页的资源。但是一般情况下不能这么做,它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。

同源策略

同源策略(SOP)是Web浏览器强制执行的一种安全策略,用于控制对网站和Web应用程序之间数据的访问。 没有SOP,任何网页都将能够访问其他页面的DOM。 这将使它可以从另一个网页访问潜在的敏感数据,以及在未经用户同意的情况下在其他网页上执行操作。

简单来说,如果JS 运行在源A 里,那么就只能获取源A 的数据不能获取源B 的数据, 即不允许跨域。

源是什么?

源= 协议+ 域名+ 端口号

如果两个url 的协议、域名、端囗号完全一致, 那么这两个url 就是同源的 举例:baidu.comwww.baidu.com 不同源,完全一致才算同源

常用的两种解决方式

但是现实中确要跨域共享内容,下面总结最常用的两种方式

CORS

CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。

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

实现CORS通信的关键是服务器,需要服务器实现了CORS接口,最关键的步骤就是在响应头中配置Access-ControI-AIIow-Origin属性

Access-ControI-AIIow-Origin:允许跨域访问的url

👉关于CORS详细的解读参考以下文章:

跨源资源共享(CORS)

跨域资源共享 CORS 详解

JSONP

JSONP是服务器与客户端跨源通信的常用方法,简单适用。

💁🏼‍♀️插一嘴:了解JSONP之前,先讨论一下在HTML文件中使用script标签引用其他网站JS文件的问题。

有时候为了方便我们会直接通过script标签在HTML中引用https://www.bootcdn.cn/等网站上的JS库,我们能成功的引用JS并成功执行相关操作,这算不算跨域呢?答案是这不是跨域,这种做法不受同源政策限制,因为只是拿来用而已,也并没有拿到JS文件中的具体内容。

因为引用JS文件不受同源政策限制,那就可以通过引入JS文件来请求服务端的数据,所以JSONP的基本思想便是网页通过添加一个<script>元素,向服务器请求JSON数据,服务器收到请求后,将数据放在一个指定名字的回调函数里传回来。

下面来简单演示一下客户端的操作:

客户端

function jsonp(url) {
  return new Promise((resolve, reject) => {
    const random = "JSONPCallbackName" + Math.random();
    window[random] = data => {
      resolve(data);//跨网站回调,等到引入JS文件拿到数据后执行
    };
    const script = document.createElement("script");
    script.src = `${url}?callback=${random}`;
    script.onload = () => {
      script.remove();
    };
    script.onerror = () => {
      reject();
    };
    document.body.appendChild(script);
  });
}

jsonp("http://example.com:8888/example.js").then(data => {
  console.log(data);
});

上面代码采用promise对JSONP进行了封装,详细步骤就是通过动态添加<script>元素来引入服务器端的JS文件,向服务器example.com发出请求,JS文件里面会执行一个回调函数 window[random],回调里面就有我们最终想要得到的数据(如果是请求JSON数据,这个回调函数就像有外边距的JSON数据,所以叫JSONP,其实它是可以携带其他类型数据的,比如HTML等)。

💁🏼‍♀️注意,回调的名字是可以是随机的,请求的查询字符串有一个callback参数,通过这个参数来指定回调函数的名字告知服务端,这对于JSONP是必需的。最后,得到数据后可用删掉script标签,以免造成HTML页面混乱。

引入的example.js文件

window[random](JSON数据)

由于<script>元素请求的JS文件可以直接作为代码运行。这时,只要浏览器定义了window[random]函数,该函数就会立即调用。作为参数的JSON数据被视为JavaScript对象,而不是字符串,因此避免了使用JSON.parse的步骤。

优点

  1. 兼容老版本IE
  2. 可以跨域访问数据

缺点

  1. 因为是script标签来请求引用的JS,所以无法像方法一中ajax请求那样可以判断整个过程的状态,并且不能拿到status和header,只能知道失败或成功,只有onload和onerror两个回调函数可用。
  2. 因为是script标签所以只能发送get请求,不支持post

两种方法的比较

  • JSONP只支持GET请求,CORS支持所有类型的HTTP请求。

  • JSONP的优势在于支持老式浏览器(IE 6,7,8,9),以及可以向不支持CORS的网站请求数据。

参考

浏览器同源政策及其规避方法