背景
有时候我们需要点击下载一些资源如excel 、pdf、 ppt、图片等,并且要支持自定义下载名字。当下载链接与当前页是同源时,可以通过a标签download属性设置,比如我在a.com打开的页面下载a.pdf
<a download="自定义名字.pdf" href="a.com/a.pdf">下载</a>
这样子同源下载的文件名就是 "自定义名字.pdf"
但是一般实际场景,文件资源都是有独立的资源服务器的,和主应用的域名不一致,上面的方法就不管用了。那么也没有其他方法呢?
方案
下载的实际原理就是前端发一个http请求去目标链接,然后资源服务器在接收请求后在response header里面设置content-type为文件流,和 Content-Disposition,例如:
Content-Type: 'application/octet-stream',
Content-Disposition: 'attachment;filename=a.pdf'
然后浏览器在接收文件流时自动采用下载的方式接收,这是浏览器自动识别的,那么有没有人工手动控制这个流程呢?其实是可以的。
搞清楚整个下载流程后,我们可以得到一个解决方案:
前端可以通过ajax去请求资源链接,因为服务端返回的是文件流,前端要接收的话,就需要知道怎么去操作文件流,前端在html5之后有个Blob对象,所以我们在请求时要设置对应的responseType:blob
就可以通过blob接收,最后把blob数据保存到本地。
具体操作如下:
利用现成工具,安装 axios 、file-saver
npm i axios file-saver -S
然后代码:
/**
* URL地址下载文件
* @param url 下载地址
* @param fileType excel | csv 或者不确定类型的,直接传类型,例如 bipkg
* @param fileName 文件名称
* @private
*/
const downloadByUrl = (url, fileType, fileName = '未命名') => {
return axios.get(url, {
responseType: 'blob',
beforeErrorAction () {
return false;
},
}).then(res => {
let mime = '';
switch (fileType) {
case 'xlsx':
mime = 'application/vnd.ms-excel';
break;
case 'csv':
mime = 'text/csv';
break;
default:
break;
}
const blob = new Blob([res], { type: mime });
fileSaver.saveAs(blob, `${fileName}.${fileType}`);
}).catch(() => {
const aTag = document.createElement('a');
aTag.href = url;
aTag.download = fileName; // 此属性仅适用于同源 URL https://developer.mozilla.org/zh-CN/docs/Web/HTML/Element/a
aTag.style.display = 'none';
document.body.appendChild(aTag);
aTag.click();
// 下载完成后删除dom节点
document.body.removeChild(aTag);
});
};
调用方法下载
downloadByUrl('xxx.com/a.pdf', 'pdf', '自定义名字')
总结
以上就是前端自定义下载文件名的解决方案,如果你有更好的方法欢迎交流。
网友评论