背景
有时候我们需要点击下载一些资源如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
pnpm i axios
然后代码:
/**
* URL地址下载文件或者接口
* @param url 下载地址
* @param ext后缀名 如 xlsx | txt | csv
* @param fileName 文件名称
* @private
*/
const downloadByUrl = (url, ext, fileName = '未命名') => {
return axios.get(url, {
responseType: 'blob'
}).then(res => {
const blob = new Blob([res]);
const href = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.setAttribute('href', href);
a.setAttribute('download', `${fileName}.${ext}`);
document.body.appendChild(a);
a.click();
document.body.removeChild(a); // 下载完成移除元素
window.URL.revokeObjectURL(href); // 释放掉blob对象
});
调用方法下载
downloadByUrl('xxx.com/a.pdf', 'pdf', '自定义名字')
总结
以上就是前端自定义下载文件名的解决方案,如果你有更好的方法欢迎交流。