# 下载文件

  • 简单的给地址url的get请求
<a href="后端文件下载接口地址" >下载文件</a>
  • fetch请求 使用 Fetch API 获取到后端返回的字节流一般都会通过 “res.blob()” 转换成 blob 对象再进一步处理(Fetch API),那么问题来了 --- ”res.blob()” 又做了什么?

每次调用 res.blob() 方法都会执行 “consume body” 动作,“consume body” 的流程大概是这样的:

  • 获取字节流的读取器
  • 通过读取器读取所有的数据
  • 把数据包装成 blob 对象并返回

自己处理字节流

fetch('example.zip')
.then((res) => {
    // 获取读取器
    const reader = res.body.getReader()
    const type = res.headers.get('Content-Type')
    const data = []

    return new Promise((resolve) => {
        // 读取所有数据
        function push() {
            reader.read().then(({done, value}) => {
                data.push(value)
                if (done) {
                    // 包装成 blob 对象并返回
                    resolve(new Blob(data, { type }))
                } else {
                    push()
                }
            })
        }
        push()
    })
})
.then(blob => {
    const url = URL.createObjectURL(blob)

    let a = document.createElement('a')
    a.download = 'example.zip'
    a.href = url
    document.body.appendChild(a)
    a.click()
    a.remove()
})
function request () {
    const req = new XMLHttpRequest();
    req.open('POST', '<接口地址>', true);
    req.responseType = 'blob';
    req.setRequestHeader('Content-Type', 'application/json');
    req.onload = function() {
      const data = req.response;
      const a = document.createElement('a');
      const blob = new Blob([data]);
      const blobUrl = window.URL.createObjectURL(blob);
      download(blobUrl) ;
    };
    req.send('<请求参数:json字符串>');
  };
 
function download(blobUrl) {
  const a = document.createElement('a');
  a.style.display = 'none';
  a.download = '<文件名>';
  a.href = blobUrl;
  a.click();
  document.body.removeChild(a);
}
 
request();
 fetch(getRootPath_web() + `YjMessageIssue/download.shtml?taskid=${ids}` , {
	method: 'POST',
})
	.then(res => res.blob())
	.then(data => {
		let blobUrl = window.URL.createObjectURL(data);
		const a = document.createElement('a');
		a.style.display = 'none';
		// a.download = '<文件名>';
		a.href = blobUrl;
		a.setAttribute('download', '报表.docx')
		document.body.appendChild(a)
		a.click();
		document.body.removeChild(a);

	});
  • 下载zip
fetch('example.zip')
.then(res => res.blob())
.then(blob => {
    // 通过 blob 对象获取对应的 url
    const url = URL.createObjectURL(blob)

    let a = document.createElement('a')
    a.download = 'example.zip'
    a.href = url
    document.body.appendChild(a)
    a.click()
    a.remove() // document.body.removeChild(a)
})
.catch(err => {
    console.error(err)
})

测试后可能会最新下载的文件回事缓存格式的(??),下新文件或者刷电脑对应的文件夹就好了

  • 原生xmlhttprequest
function request () {
    const req = new XMLHttpRequest();
    req.open('POST', '<接口地址>', true);
    req.responseType = 'blob';
    req.setRequestHeader('Content-Type', 'application/json');
    req.onload = function() {
      const data = req.response;
      const a = document.createElement('a');
      const blob = new Blob([data]);
      const blobUrl = window.URL.createObjectURL(blob);
      download(blobUrl) ;
    };
    req.send('<请求参数:json字符串>');
  };
 
function download(blobUrl) {
  const a = document.createElement('a');
  a.style.display = 'none';
  a.download = '<文件名>';
  a.href = blobUrl;
  a.click();
  document.body.removeChild(a);
}
 
request();

实际测试有问题,报错,等待查验

# 利用插件下载文件 js-file-download

cnpm install js-file-download
import axios form 'axios'
import qs from 'qs'

// 参数
const body = {
        fileId: this.fileId
 }
try {
        axios.get('url', { params: body,  responseType: 'arraybuffer' }).then(res => {
               JsFileDownload(res.data, `测试文件_${new Date().toLocaleString()}.xls`)
        })
 } catch (e) { throw new Error(e) }
      axios({
          url: '/api/system/file/download/by/fileId',
          method: 'post',
          data: qs.stringify(body),
          headers: {
            'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8;'
          },
          responseType: 'arraybuffer'
        }).then(res => {
          JsFileDownload(res.data, `解析错误文件详情_${new Date().toLocaleString()}.xls`)
        })
import fileDownload from 'js-file-download';
import Axios from 'axios'
import store from '@/store'

download() {
    var requestUrl = "tcmp/api/devices/model";
    var Authorization = store.state.user.token;
    Axios({
       method: 'get',
       url: requestUrl,
       headers: {
          'Authorization': Authorization
       },
       responseType: 'blob'
       }).then(res => {
           fileDownload(res.data, 'deviceModel.xlsx');
       });
}

responseType: 'arraybuffer'缺了会乱码,当然,也可以是其他的类型如blob

export function exportAlertInfo(data) {
  return request({
    url: '/openIot/backend/access/exportAlertInfo',
    method: 'post',
    data,
    responseType: 'arraybuffer',
    headers: {
      Accept: 'application/json'
    }
  })
}

# 在欣方手写的垃圾代码,responseType为blob

    $("#changemes").on('click',function(e){
        var canshu= e.target.innerHTML;

        var mes=JSON.stringify({file:canshu})
        var url = "https://op.cintelcloud.com:6688/FileImgDownload/";
            var xhr = new XMLHttpRequest();
            xhr.open("POST", url);
            xhr.setRequestHeader(
              "x-header-token",
              localStorage.getItem("Token")
            );
        xhr.setRequestHeader("Content-Type","application/x-www-form-urlencoded");
        xhr.responseType = "blob";  
        xhr.send(mes);
         xhr.onreadystatechange = function() {
              if (xhr.readyState == 4 && xhr.status == 200) {
                   var blob = this.response;
                        if(blob.size>0){
                            var reader = new FileReader();
                            reader.readAsDataURL(blob);   // 转换为base64,可以直接放入a标签href
                            reader.onload = function (e) {
                                // 转换完成,创建一个a标签用于下载
                                var a = document.createElement('a');
                                a.download = canshu;
                                a.href = e.target.result;
                                $("body").append(a);    // 修复firefox中无法触发click
                                a.click();
                                $(a).remove();
                                // window.location.reload();
                            }
                        }
              }
            };
       
    } )
    downexecl() {
      exportAlertInfo(this.alarmForm).then(res => {
		//res是ArrayBuffer
		//方法一
		//const blob = new Blob([res]);
		//console.log(blob)
		//const url = URL.createObjectURL(blob)
		// let a = document.createElement('a')
		// a.download = 'example.xls'
		// a.href = url
		// document.body.appendChild(a)
		//a.click()
		//document.body.removeChild(a)
       
	    //方法二
        fileDownload(res, '告警数据信息.xls')
        setTimeout(() => {
          loading.close()
        }, 1000)
      }).catch(() => {
        loading.close()
      })
    },

一种转url方法,借助blob转url,使用插件fileDownload

# 下载闪烁问题

使用a标签或者window.open可能会存在闪烁问题

const iframe = document.createElement('iframe')
  iframe.src = tem
  iframe.style.display = 'none'
  document.body.appendChild(iframe)
  setTimeout(() => {
    document.body.removeChild(iframe)
  }, 1000)

# 下载流文件异常情况的处理

downloadBlob(url) {
    downloadByUrl(url).then((res) => {
        let { data } = res
        if (data.type === 'application/json') {
            let reader = new FileReader()
            reader.addEventListener('loadend', () => {
                const { message } = JSON.parse(reader.result)
                this.$message.error(message || '下载失败')
            })
            reader.readAsText(data, 'utf-8')
        } else {
            let blob = new Blob([data])
            let elink = document.createElement('a')
            elink.download = data.attachSaveName
            elink.style.display = 'none'
            elink.href = URL.createObjectURL(blob)
            document.body.appendChild(elink)
            elink.click()
            URL.revokeObjectURL(elink.href) // 释放URL 对象
            document.body.removeChild(elink)
        }
    })
}

本地测成功线上失败因为http被谷歌认为不安全 (opens new window)

最后更新: 10/14/2024, 8:20:19 AM