vue接收后端返回的文件流,下载文件(post和get)。前端的集中文件下载方式。大文件下载

后台返回一个File类型(文件流、byte)的数据给前端。

前端请求的时候(建议小文件可以使用blob。大文件使用的时候,在获取文件流需要时间,等待时间会很久)

1、设置返回类型responseType,不管你用post\get\ect都要设置,还有post请求要设置content-type:multipart/from-data(跟文件上传一样,是接收文件的)

2、使用blob类型接收

3、销毁URL对象

//post请求要设置header
axios.post("you api",options,{
            responseType: 'blob',//设置返回类型
          },
          {
             headers:{
                 "content-type":"multipart/from-data",
             }
        }).then((res)=>{
            const link=document.createElement('a');
            try {
              //如果文件类型不确定的时候,可以不设置type
              let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'});

              let _fileName = res.headers['content-disposition'].split(';')[1].split('=')
[1];//文件名,中文无法解析的时候会显示 _(下划线),生产环境获取不到
              link.style.display='none';
              // 兼容不同浏览器的URL对象
              const url = window.URL || window.webkitURL || window.moxURL;
              
              link.href=url.createObjectURL(blob);
              link.setAttribute('download', _fileName.substring(_fileName.lastIndexOf('_')+1)));
              document.body.appendChild(link);
              link.click();
              document.body.removeChild(link);
              url.revokeObjectURL(link.href);//销毁url对象
            }catch (e) {
              console.log('下载的文件出错',e)
            }

          }).catch((err)=>{
           console.log('请求出错',err.response.data.error);
          })


//get请求
axios.get("you api",{
            responseType: 'blob',//设置返回类型
          }).then((res)=>{
            const link=document.createElement('a');
            try {
              let blob = new Blob([res.data],{type: 'application/vnd.ms-excel'});
              let _fileName = res.headers['content-disposition'].split(';')[1].split('=')[1];//文件名,中文无法解析的时候会显示 _(下划线),生产环境获取不到
              link.style.display='none';
              // 兼容不同浏览器的URL对象
              const url = window.URL || window.webkitURL || window.moxURL;
              
              link.href=url.createObjectURL(blob);
              
     link.setAttribute('download', _fileName.substring(_fileName.lastIndexOf('_')+1)));
              document.body.appendChild(link);
              link.click();
              document.body.removeChild(link);
              url.revokeObjectURL(link.href);//销毁url对象
            }catch (e) {
              console.log('下载的文件出错',e)
            }
  }).catch(()=>{

  })

另外,我发现npm run build之后,前端的获取到的请求头是这样的,没有filename,不能获取到文件名

但浏览器获取到的是完整的。

所以后端的接口中要设置headers下面的属性,就可以获取到文件名了。(这个需要后端设置)

Access-Control-Expose-Headers: Content-Disposition

2、前端的几种文件下载方式

前端vue中实现文件下载的几种方法_小太阳的博客-优快云博客_前端vue实现文件下载

需要设置token的时候,还是使用responseType:'blob‘方式吧,不要直接用<a>标签。另外要设置header的

3、大文件下载还想用浏览器自带的下载功能时(如下图),放开token ,直接使用<a href="'下载地址'" download="‘设置文件名’"></a>

大文件分片下载是一种常见的下载方式,可以通过将大文件分成多个小文件下载,从而提高下载速度稳定性。在 Vue SpringBoot 中,可以通过以下步骤实现大文件分片下载: 1.大文件分成多个小文件,每个小文件大小为固定的值,比如1MB或2MB。 2.前端 Vue 中,使用 axios 发送请求,并设置请求头 Range,表示请求文件的某个片段。 3.后端 SpringBoot 中,接收前端请求,并根据请求头 Range,返回对应的文件片段。 4. 前端 Vue 接收到多个文件片段后,将它们合并成一个完整的文件。 5. 下载完成后,将多个小文件删除,以释放存储空间。 具体实现细节可以参考以下代码: 前端 Vue: ``` downloadFile() { const url = '/api/download'; const file_name = 'large_file.mp4'; const chunk_size = 2 * 1024 * 1024; // 2MB per chunk const total_size = 1024 * 1024 * 1024; // 1GB const total_chunks = Math.ceil(total_size / chunk_size); const headers = { 'Content-Type': 'application/json' }; axios.post(url, { file_name, chunk_size, total_size }, { headers }) .then(res => { const { data } = res; const blobs = data.map((chunk, index) => { return new Blob([chunk], { type: 'application/octet-stream' }); }); const blob = new Blob(blobs, { type: 'application/octet-stream' }); const object_url = window.URL.createObjectURL(blob); const link = document.createElement('a'); link.href = object_url; link.download = file_name; link.click(); window.URL.revokeObjectURL(object_url); }); } ``` 后端 SpringBoot: ``` @PostMapping("/download") public List<byte[]> downloadFile(@RequestBody Map<String, Object> params, HttpServletRequest request, HttpServletResponse response) throws IOException { String file_name = (String) params.get("file_name"); int chunk_size = (int) params.get("chunk_size"); int total_size = (int) params.get("total_size"); int total_chunks = (int) Math.ceil((double) total_size / chunk_size); String range_header = request.getHeader("Range"); if (range_header == null) { response.setStatus(HttpServletResponse.SC_BAD_REQUEST); return null; } String[] range = range_header.split("=")[1].split("-"); int start = Integer.parseInt(range[0]); int end = range.length > 1 ? Integer.parseInt(range[1]) : start + chunk_size - 1; if (end >= total_size) { end = total_size - 1; } response.setHeader("Content-Type", "application/octet-stream"); response.setHeader("Content-Length", String.valueOf(end - start + 1)); response.setHeader("Content-Range", "bytes " + start + "-" + end + "/" + total_size); response.setHeader("Accept-Ranges", "bytes"); response.setStatus(HttpServletResponse.SC_PARTIAL_CONTENT); RandomAccessFile file = new RandomAccessFile(file_name, "r"); file.seek(start); byte[] bytes = new byte[chunk_size]; List<byte[]> chunks = new ArrayList<>(); int read = 0; while (read < chunk_size && start + read <= end) { int n = file.read(bytes, read, chunk_size - read); if (n <= 0) { break; } read += n; } chunks.add(Arrays.copyOf(bytes, read)); file.close(); return chunks; } ```
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值