一网打尽,最全面的跨域解决方案来了!
共 7218字,需浏览 15分钟
·
2021-12-23 14:31
今天我们来聊一个老生常谈的话题,跨域!又是跨域,烦不烦 ?网上跨域的文章那么多,跨的我眼睛都疲劳了,不看了不看了 别走...
我尽量用最简单的方式将常见的几种跨域解决方案给大家阐释清楚,相信认真看完本文,以后不管是作为受试者还是面试官,对于这块的知识都能够游刃有余。
什么是“跨源”
不是讲跨域吗 ?怎么又来个“跨源” ?字都能打错的 ? ...稍安勿躁,其实我们平常说的跨域是一种狭义的请求场景,简单来说,就是“跨“过浏览器的同源策略去请求资“源”,所以我们叫它“跨源”也没啥问题。那么,跨源,源是什么?浏览器的同源策略什么是同源?协议,域名,端口都相同就是同源干巴巴的,能不能举个栗子?栗子:),有的有的:
const url = 'https://www.google.com:3000'
比如上面的这个 URL,协议是:https,域名是 www.google.com,端口是 3000。不同源了会怎么样?会有很多限制,比如:
Cookie,LocalStorage,IndexDB 等存储性内容无法读取
DOM 节点无法访问
Ajax 请求发出去了,但是响应被浏览器拦截了
我就想请求个东西,至于吗,为什么要搞个这么个东西限制我?基于安全考虑,没有它,你可能会遇到:
Cookie劫持,被恶意网站窃取数据
更容易受到 XSS,CSRF 攻击
无法隔离潜在恶意文件
... ...
所以,得有。正是因为浏览器同源策略的存在,你的 Ajax 请求有可能在发出去后就被拦截了,它还会给你报个错:
✘ Access to XMLHttpRequest at 'xxx' from origin 'xxx' has been block by CORS,
policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
这种发出去拿不到响应的感受,就像你在网上冲浪时,被一股神秘的东方力量限制了一样:
非常难受,所以,我们接下来就来看看怎么用科学的方法解决跨域的问题。
JSONP
这玩意儿就是利用了 标签的 src 属性没有跨域限制的漏洞,让我们可以得到从其他来源动态产生的 JSON 数据。为什么叫 JSONP ?JSONP 是 JSON with Padding 的缩写,额,至于为什么叫这个名字,我网上找了下也没个标准的解释,还望评论区的各位老哥知道的赶紧告诉我: )怎么实现 ?具体实现思路大致分为以下步骤:
本站的脚本创建一个 元素,src 地址指向跨域请求数据的服务器
提供一个回调函数来接受数据,函数名可以通过地址参数传递进行约定
服务器收到请求后,返回一个包装了 JSON 数据的响应字符串,类似这样:callback({...})
浏览器接受响应后就会去执行回调函数 callback,传递解析后的 JSON 对象作为参数,这样我们就可以在 callback 里处理数据了。实际开发中,会遇到回调函数名相同的情况,可以简单封装一个 JSONP 函数:
function jsonp({ url, params, callback }) {
return new Promise((resolve, reject) => {
// 创建一个临时的 script 标签用于发起请求
const script = document.createElement('script');
// 将回调函数临时绑定到 window 对象,回调函数执行完成后,移除 script 标签
window[callback] = data => {
resolve(data);
document.body.removeChild(script);
};
// 构造 GET 请求参数,key=value&callback=callback
const formatParams = { ...params, callback };
const requestParams = Object.keys(formatParams)
.reduce((acc, cur) => {
return acc.concat([`${cur}=${formatParams[cur]}`]);
}, [])
.join('&');
// 构造 GET 请求的 url 地址
const src = `${url}?${requestParams}`;
script.setAttribute('src', src);
document.body.appendChild(script);
});
}
// 调用时
jsonp({
url: 'https://xxx.xxx',
params: {...},
callback: 'func',
})
我们用 Promise 封装了请求,使异步回调更加优雅,但是别看楼上的洋洋洒洒写了一大段,其实本质上就是: