同源策略、CORS、JSONP~
跨域问题的产生
跨域是指从一个源的网页去请求另一个源的网页的资源。但是一般情况下不能这么做,它是由浏览器的同源策略造成的,是浏览器对JavaScript施加的安全限制。
同源策略
同源策略(SOP)是Web浏览器强制执行的一种安全策略,用于控制对网站和Web应用程序之间数据的访问。 没有SOP,任何网页都将能够访问其他页面的DOM。 这将使它可以从另一个网页访问潜在的敏感数据,以及在未经用户同意的情况下在其他网页上执行操作。
简单来说,如果JS 运行在源A 里,那么就只能获取源A 的数据不能获取源B 的数据, 即不允许跨域。
源是什么?
源= 协议+ 域名+ 端口号
如果两个url 的协议、域名、端囗号完全一致, 那么这两个url 就是同源的 举例:https://baidu.com 、https://www.baidu.com 不同源,完全一致才算同源
常用的两种解决方式
但是现实中确要跨域共享内容,下面总结最常用的两种方式
CORS
CORS是一个W3C标准,全称是"跨域资源共享"(Cross-origin resource sharing)。
CORS需要浏览器和服务器同时支持。目前,所有浏览器都支持该功能,IE浏览器不能低于IE10。
实现CORS通信的关键是服务器,需要服务器实现了CORS接口,最关键的步骤就是在响应头中配置Access-ControI-AIIow-Origin属性
Access-ControI-AIIow-Origin:允许跨域访问的url
👉关于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
的步骤。
优点
- 兼容老版本IE
- 可以跨域访问数据
缺点
- 因为是script标签来请求引用的JS,所以无法像方法一中ajax请求那样可以判断整个过程的状态,并且不能拿到status和header,只能知道失败或成功,只有onload和onerror两个回调函数可用。
- 因为是script标签所以只能发送get请求,不支持post
两种方法的比较
-
JSONP只支持
GET
请求,CORS支持所有类型的HTTP请求。 -
JSONP的优势在于支持老式浏览器(IE 6,7,8,9),以及可以向不支持CORS的网站请求数据。