主要原理
前端
<!-- 其中的 download 提示浏览器下载而不是打开 -->
<a href="http://xxxx.com/yyy.txt" downlod="yyy.txt"></a>
后端
后端的设置主要是为了当浏览不支持 download
属性的时候的兼容性。
res.setContentType("application/octet-stream");
res.addHeaders("Content-Disposition", "attachment;filename=" + filename);
res.addHeaders("Content-Length", content.length);
参考
推荐的 a 标签的方式
/**
* @param {string} url 下载链接
* @param {string} filename 保存到本地的文件名
*/
var fileDownload = function(url, filename) {
var hiddenALink = document.createElement('a');
// 设置下载链接
hiddenALink.href = url;
// 设置保存到本地的文件名
hiddenALink.download = filename;
// 设置在页面上不显示
hiddenALink.style.display = 'none';
// 因为 Firefox 兼容性问题,必须要 append 到页面
document.body.appendChild(hiddenALink);
hiddenALink.click(); // 点击操作
document.body.removeChild(hiddenALink);
}
在 Chrome 中 appendChild(hiddenALink)
的操作可以省去直接 click()
,但是在 FireFox 中却不可以,必须要 appendChild()
才可以 click()
,具体可参考 stackoverflow programmatical-click-on-a-tag-not-working-in-firefox。
优点
- 简单,直观,方便
缺点
- 需要传递较多参数时略麻烦
- 某些情况下的鉴权会不可用
当点击下载,出现的却是 html 文件或者 json 文件的时候,考虑下是不是要放开后端的 security 匿名访问。
ajax blob 形式下载
/**
* 不管是用的原生的 XMLHttpRequest 还是 axios 封装好的
*
* 其最主要的一个点是 responseType: 'blob'
*/
var fileDownload = function(url, filename) {
axios.get(url, {
// 这里可以添加其他参数
// 比如用于筛选数据的,鉴权的
responseType: 'blob'
}).then(res => {
// 此时是已经下载完了的内容
// 如果在下载过程中,没有关于进度的处理,将没有任何提示
// 小文件速度很快,几乎无影响,大文件会有一段儿时间的,无反应等待
// axios 的 res 里的 data 才是 blob 的内容
const content = res.data;
// 这里把下载完的内容,搞成了 ObjectURL
const furl = window.URL.createObjectURL(content);
// 到这里又可以调用上面那个 a 标签的方式了
download0(furl, filename);
})
}
/**
* 这就是上面 a 标签那个
*
* @param {string} url 下载链接
* @param {string} filename 保存到本地的文件名
*/
var download0 = function(url, filename) {
var a = document.createElement('a');
a.href = url;
a.download = filename;
a.style.display = 'none';
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
}
优点
- 传递参数方便
缺点
- 超大文件的时候,对客户端的内存不友好
- 超大文件在页面没有做关于下载进度处理的情况下,看不到下载进度,体验不友好
适用场景
- 小文件
- 需要传递较多参数