# 文件下载

# MiMe-Type

通过设置header中的Content-Disposition,指示响应头回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地。

MDN (opens new window)

//
Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"
Content-Disposition: form-data
Content-Disposition: form-data; name="fieldName"
Content-Disposition: form-data; name="fieldName"; filename="filename.jpg"
1
2
3
4
5
6
7

文件流下载: 比如 pdf 或者 Excel时,一般是直接点击一个连接就可以直接下载,这一般是文件流的下载方式。

通过代码设置

Response.AppendHeader("Content-Disposition","attachment;filename=FileName.txt"); 
1

通过nginx设置

https://blog.csdn.net/u011519550/article/details/104419016

location ~ ^/file  {
    if ($request_filename ~* ^.*?\.(txt|doc|pdf)$){
            add_header Content-Disposition: 'attachment';
            add_header  Content-Type application/octet-stream;
    }        
    root /home/wangjinyu;
1
2
3
4
5
6

# GET下载

let url =  xxxx.action?a=xx&b=yy;
 window.location.href = url;
 // 或者
 window.open(url, '_self')
1
2
3
4

# POST下载(form表单)

form表单下载

https://www.cnblogs.com/shengmo/p/10812481.html

// 导出excel
postExcelFile(params, url) {
  //params是post请求需要的参数,url是请求url地址
  var form = document.createElement('form')
  form.style.display = 'none'
  form.action = url
  form.method = 'post'
  document.body.append(form)
  // 动态创建input并给value赋值
  for (var key in params) {
    var input = document.createElement('input')
    input.type = 'hidden'
    input.name = key
    input.value = params[key]
    form.appendChild(input)
  }
  form.submit()
  form.remove()
}

//调用
this.postExcelFile({ currentPage: 2, pageSize: 20 }, 'url/xxxxxxx/')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

form表单无法添加Request Header,如涉及到请求头,需要使用Ajax

# 创建a标签下载

const downloadFile = async (fileName: string) => {
  const blob = await getFileBlob(fileName);
  if (blob) {
    // 创建一个隐藏的 <a> 标签来触发下载
    const link = document.createElement('a');
    link.href = URL.createObjectURL(blob);
    link.download = fileName.split('/').pop() || fileName; // 获取文件名
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
    URL.revokeObjectURL(link.href); // 释放内存
  } else {
      alert(`无法下载文件 ${fileName}`);
  }
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# Ajax通过二进制流下载文件

https://blog.csdn.net/weixin_43487782/article/details/109604950

URL.createObjectURL() 静态方法会创建一个 DOMString (opens new window),其中包含一个表示参数中给出的对象的URL。这个 URL 的生命周期和创建它的窗口中的 document (opens new window) 绑定。这个新的URL 对象表示指定的 File (opens new window) 对象或 Blob (opens new window) 对象。 createObjectURL()支持传入 File (opens new window) 对象、Blob (opens new window) 对象或者 MediaSource (opens new window) 对象(媒体资源)。

注意:URL.createObjectURL()创建的对象使用完成后,即下载后可以通过URL.revokeObjectURL()移除该对象,释放内存。理论上讲dom销毁时,URL.createObjectURL()创建的对象也会随之销毁,我们可以不必手动销毁。但当页面有类似表格形式的文件列表时,下载完文件立即手动销毁对象无疑是最好的选择。

async function qualityExport() {
  let res = await getQualityExport()
  this.downloadFile(
    res.data,
    moment().format('YYYYMMDDHHmm'),
    'application/vnd.ms-excel;charset=utf-8'
  )
}
/**
 * @param {ArrayBuffer|Blob} data 二进制数据
 * @param {String} fileName 文件名
 * @param {String} mimeType 文件mime类型
 */
function downloadFile(data, fileName, mimeType) {
  let blob = new Blob([data], {
    type: mimeType,
  })
  let URL = window.URL || window.webkitURL
  let objectUrl = URL.createObjectURL(blob)
  let a = document.createElement('a')
  a.href = objectUrl // 文件流生成的url
  a.download = `${fileName}.xlsx` // 文件名
  document.body.appendChild(a)
  a.click()
  a.remove()
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26

blob遇到的坑

axios封装时没有处理res.data为二进制数据时的状况,在响应拦截器加上二进制数据的判断,原样返回res

if (Object.prototype.toString.call(data.data) === '[object ArrayBuffer]') {
  return data
}
// or
if (data.headers['content-type'] === 'application/vnd.ms-excel;charset=utf-8') {
  return data
}
1
2
3
4
5
6
7
image-20210622171600407

# Blob、ArrayBuffer和Buffer

# Blob

new Blob( array, options );
1

https://zhuanlan.zhihu.com/p/97768916

# ArrayBuffer是原始的二进制数据缓冲区

# Buffer和Stream

https://zhuanlan.zhihu.com/p/31355139

https://segmentfault.com/a/1190000011968267

# 问题

ajax调下载接口后返回到数据如下

image-20211231153639462

正常应该返回一个ArrayBuffer

原因: 二进制流下载,后端返回的Response Content-Type 需要是 APPLICATION/OCTET-STREAM;。

如果返回的是application/vnd.ms-excel;就会出现上述问题