图片下载本地报跨域
一、 背景
在开发的附件下载组件中,后端返回的图片链接无法使用a标签添加download属性下载本地,只能在另一个窗口打开。所以为了解决产品提出的这个需求。 我采用fetch请求的方式下载到本地。然后遇到了图片报错跨域问题。
报错信息:
二、 问题梳理
2.1 关于图片下载的方法
从报错信息上看,就是图片下载的时候出现跨域头的问题,于是联系了后端。后端竟然说不知道怎么设置。还要找他们的组长看。于是为了解决这个问题。 我在网上查找了很多种方法。起初用fetch,设置mode,发现不报跨域的错了。但是无法拿到请求的资源,甚至有时候可以下载本地。有时候不可以。然后又采用了转二进制,转base64,以及使用canvas等。最后发现都不行。最后在网上看到有人说是缓存的问题。于是,我就清除缓存试了试,发现问题一下解决了。
2.2 问题概括
因为封装的附件下载组件支持所有格式的文件预览,在预览的同时就会去渲染这个图片链接,通过img标签展示出来。通过 'img' 加载的图片,浏览器默认情况下会将其缓存起来。当我再去请求这个链接的时候,因为缓存中已经存在啦。所以浏览器直接拒绝,报错跨域。
三、 解决问题
因为在预览的时候,我已经请求一次这个图片地址并用来展示,而当我才用fetch请求的时候,因为img默认没有设置跨域请求属性,而我的fetch请求是属于跨域请求 ,所以,只要在img标签上加上crossOrigin="anonymous"
采用跨域请求资源。这个时候。当我们再去跨域请求的时候就不会被浏览器拒绝。
四、 总结
我们要弄清楚问题的原因所在。在这里一种是后端没有设置跨域头的问题。这个需要后端设置。一种是我们本地缓存问题造成的跨域。 所以如果你已经看到这里了,要冷静思考。问题的原因所在。如果有的图片可以下载,有的图片不可以下载,那你就打开前端控制台。点击
Network
选项卡。勾选Disble cache
,意思是不缓存。然后你在点击下载。看看是不是可以下载。如果可以下载。那就是本地缓存的问题无疑。看看是不是用到了img标签。在这里:如果像我这种问题。fetch请求跨域图片地址。img展示的时候也要相应的设置
crossOrigin="anonymous"
,都采用跨域请求。才不会跨域。
五、 附上我的完整代码
5.1 图片设置跨域属性
<img height={650} src={url} crossOrigin="anonymous" role="presentation" />
5.2 js请求的方法
/**
* 图片下载到本地
* @param {string} name 图片名称
* @param {string} url 图片地址
* 解决图片资源请求跨域问题
*/
downloadWithBlob(name, url) {
/* 常见资源类型
1.excel: type = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
2.图片: type = "image/*"
3.视频: type = "video/*"
4.音频: type = "audio/*"
*/
window.fetch(url, {
mode: 'cors',
}).then((response) => {
// 拿到arrayBuffer 转化为 blob 生成链接 通过a标签打开
response.arrayBuffer().then((res) => {
const type = 'image/*'; // 资源类型
// eslint-disable-next-line no-undef
const blob = new Blob([res], { type });
const objectUrl = window.URL.createObjectURL(blob);
const a = window.document.createElement('a');
window.document.body.appendChild(a);
a.style = 'display: none';
a.href = objectUrl;
a.download = name;
a.click();
window.document.body.removeChild(a);
});
});
}
最后,感谢你能读到并读完此文章,如果分析的过程中存在错误或者疑问都欢迎留言讨论。如果我的分享能够帮助到你。麻烦github 点波关注。🚗。