耀极客论坛

 找回密码
 立即注册
查看: 391|回复: 0

javascript Blob对象实现文件下载

[复制链接]

336

主题

318

帖子

22万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
220555
发表于 2022-5-8 02:25:32 | 显示全部楼层 |阅读模式
  这篇文章主要为大家介绍了vue组件通信的几种方法,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助


说明
  最近遇到一个需求,文件下载,但需要鉴权,这就意味着不能用后台返回下载链接的方式进行下载,因为一旦被别人拿到这条链接,就可以不需要任何权限就直接下载,因此需要换种思路,在一番百度之后,了解到了blob对象,这就是本文要讲的内容
  注意:本文仅为记录学习轨迹,如有侵权,联系删除

一、Blob对象
  Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。

二、前端
  blob下载思路:
  1. 1) 使用ajax发起请求,指定接收类型为blob(responseType: ‘blob')
  2. 2)读取请求返回的头部信息里的content-disposition,返回的文件名就在这里面(或者自定义文件名,可跳过此步骤)
  3. 3)使用URL.createObjectURL将请求的blob数据转为可下载的url地址
  4. 4)使用a标签下载
复制代码
  代码:
  1. // 下载
  2. export function download(query,newFileName) {
  3.   return request({
  4.     url: '/file/download',
  5.     method: 'get',
  6.     responseType: 'blob',
  7.     params: query
  8.   }).then((res) => {
  9.     /**
  10.      * blob下载思路
  11.      * 1) 使用ajax发起请求,指定接收类型为blob(responseType: 'blob')
  12.      * 2)读取请求返回的头部信息里的content-disposition,返回的文件名就在这里面(或者自定义文件名,可跳过此步骤)
  13.      * 3)使用URL.createObjectURL将请求的blob数据转为可下载的url地址
  14.      * 4)使用a标签下载
  15.      *
  16.      */
  17.     let blob = res.data
  18.     // 从response的headers中获取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 设置的文件名;
  19.     // let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
  20.     // let contentDisposition = decodeURI(res.headers['content-disposition'])
  21.     // let result = patt.exec(contentDisposition)
  22.     // let fileName = result[1]
  23.     //将请求的blob数据转为可下载的url地址
  24.     let url = URL.createObjectURL(blob)
  25.     // 创建一个下载标签‹a>
  26.     const aLink = document.createElement('a')
  27.     aLink.href = url
  28.     // 2.直接使用自定义文件名,设置下载文件名称
  29.     aLink.setAttribute('download', newFileName )
  30.     document.body.appendChild(aLink)
  31.     // 模拟点击下载
  32.     aLink.click()
  33.     // 移除改下载标签
  34.     document.body.removeChild(aLink);
  35.   })
  36. }
复制代码
  调用该方法
  1. //下载
  2.     download(row) {
  3.       // filePath:文件路径,例如:e:\upload\
  4.   // fileName:文件名, 例如:a.xlsx
  5.       let form = {
  6.         filePath: row.filePath,
  7.         fileName: row.fileName,
  8.       };
  9.       //下载,row.fileOriginalName是文件的原始名称,仅仅用于文件下载时起个名字而已
  10.       download(form, row.fileOriginalName);
  11.     }
  12. // 由于本人使用的是阿里的oss服务,所以只需要传个文件路径回去后端,根据文件路径查询oss接口得到返回的文件流即可,例如(BufferedInputStream),在响应头设置好返回的类型即可
复制代码
三、后端
  1. 后端这里用了阿里的oss服务,直接拿到文件流(new BufferedInputStream(ossObject.getObjectContent())),如果是非oss的情况下,只需要读取对应服务器上面的文件(File),转成BufferedInputStream后,直接套用下面的代码即可(即通过response.getOutputStream()设置BufferedOutputStream 就行了)
复制代码
  1. // response:响应
  2. // filePath:文件路径,例如:e:\upload\
  3. // fileName:文件名, 例如:a.xlsx
  4.    public void download(HttpServletResponse response, String filePath, String fileName) {
  5.         //待下载文件名
  6.         response.reset();
  7.         response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
  8.         response.setContentType("application/octet-stream");
  9.         response.setCharacterEncoding("utf-8");
  10.         // 创建OSSClient实例。
  11.         OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
  12.         // ossObject包含文件所在的存储空间名称、文件名称、文件元信息以及一个输入流。
  13.         OSSObject ossObject = ossClient.getObject(bucketName, filePath + "/" + fileName);
  14.         BufferedInputStream in = null;
  15.         BufferedOutputStream out = null;
  16.         byte[] buff = new byte[1024];
  17.         int length = 0;
  18.         try {
  19.             in = new BufferedInputStream(ossObject.getObjectContent());
  20.             out = new BufferedOutputStream(response.getOutputStream());
  21.             while ((length = in.read(buff)) != -1){
  22.                 out.write(buff,0,length);
  23.             }
  24.         } catch (IOException e) {
  25.             e.printStackTrace();
  26.         } finally {
  27.             if(out != null){
  28.                 try {
  29.                     out.flush();
  30.                     out.close();
  31.                 } catch (IOException e) {
  32.                     e.printStackTrace();
  33.                 }
  34.             }
  35.             if(in != null){
  36.                 try {
  37.                     in.close();
  38.                 } catch (IOException e) {
  39.                     e.printStackTrace();
  40.                 }
  41.             }
  42.             if (ossClient != null) {
  43.                 ossClient.shutdown();
  44.             }
  45.         }
  46.     }
复制代码
总结

  本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|耀极客论坛 ( 粤ICP备2022052845号-2 )|网站地图

GMT+8, 2022-12-10 02:30 , Processed in 0.094629 second(s), 29 queries .

Powered by Discuz! X3.4

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表