b5的下载的demo在哪_从 bug 中学习文件下载

6691e1aca044e7d2be20fe485449f461.png

背景

某日接到用户反馈,说某个模块下载文件失败,查看用户截图后确认问题如下:

  • 系统:windows
  • 浏览器:搜狗(发现只有该浏览器有问题 )
  • 下载框中看到,浏览器没有正确识别文件名称及后缀,而是把接口路径的最后一段作为文件名,导致无法打开文件

经过排查发现,与 a 标签的 download 属性的设置有关,这就引出了问题,下载文件是如何实现的,下载文件名是如何确定的,于是有了这篇总结,下面开始进入正题 (●゚ω゚●)

业务代码中前端下载文件的逻辑是参考 file-saver 实现的

function downloadFile(url: string, fileName: string = '') {
  const a = document.createElement('a');
  a.download = fileName;
  a.rel = 'noopener'; // tabnabbing, 防止打开的窗口获取操作源窗口的 window 对象
  a.href = url;
  a.target = '_blank';
  // `a.click()` doesn't work for all browsers (#465)
  try {
    a.dispatchEvent(new MouseEvent('click'));
  } catch (e) {
    const evt = document.createEvent('MouseEvents');
    evt.initMouseEvent(
      'click',
      true,
      true,
      window,
      0,
      0,
      0,
      80,
      20,
      false,
      false,
      false,
      false,
      0,
      null
    );
    a.dispatchEvent(evt);
  }
}

后端下载文件接口的响应头如下:

Content-Disposition: attachment; filename*=UTF-8''%E6%B5%8B%E8%AF%95.xlsx
Content-Type: application/octet-stream

<a> download vs Content-Disposition

<a> download 属性

<a>: The Anchor element​developer.mozilla.org
e741909abba09de6311f1791a397d907.png

功能

下载目标链接而不是导航到目标链接

使用场景

对于浏览器可识别的文件格式,如图片,txt,pdf 等,使用 download 属性可实现文件下载,否则会在浏览器窗口中打开文件预览

使用方式

<a href="xxx" download>xxx</> // 表示超链接用于下载而不是跳转
<a href="xxx" download="xxx.xx">xxx</> // 指定下载文件的名字

使用限制

  • 同域链接
  • data:URL
  • blob:URL

download 属性为空时,filename 的确定

  • filename: Content-Disposition 的 filename 字段 / The final segment in the URL path
  • extension: Content-Type / start of the data:URL / Blob.type for the blob:URL
注:当 Content-Disposition 的 filename 与 download 值不同时,filename 的优先级更高The attribute can furthermore be given a value, to specify the file name that user agents are to use when storing the resource in a file system. This value can be overridden by the `​Content-Disposition​` HTTP header's filename parameters.

Content-Disposition

作为 HTTP 响应头时,语法如下:

Content-Disposition: inline
Content-Disposition: attachment
Content-Disposition: attachment; filename="filename.jpg"; filename*=ext-value

Disposition Type

  • inline: 表示响应作为网页或网页的一部分在浏览器中展示
  • attachment: 表示响应作为附件下载并保存到本地

Filename

  • filename
    • 支持 ISO-8859-1 字符集
    • 作为保存文件时呈现给用户的文件名
    • 当 Disposition Type 为 inline 时,作为用户后续保存文件时的文件名称(如右键另存为的情况)
  • filename*
    • 与 filename 的区别是,filename * 支持 ISO-8859-1 字符集之外的字符
    • 按照 RFC 5987 中的编码方式编码
    • 当与 filename 同时存在时,filename* 的优先级更高
ISO-8859-1 是 ASCII 字符集的扩展,加入了 96 个字母及符号,以供使用附加符号的拉丁字母语言使用

Filename 编码问题

最初 http 头的值只支持 ASCII 码,直到 RFC 5987 提出了统一的编码方式,使用扩展参数:

parameter*=charset'lang'value

其中:

  • charset 必填,ASCII 字符,不区分大小写
  • lang 选填,ASCII 字符,不区分大小写
  • value 原始名称经过指定编码后再经过百分号编码的值
  • 三者以 ' 分隔
  • 浏览器应至少支持 ASCII 编码和 utf-8 编码
  • 当参数值格式错误或无法解析是,会忽略该参数
  • 出于安全考虑,如果 filename 的值带有 / 会被转成 _ 的形式

小结

  • download 属性一般用于纯前端的下载
  • Content-Disposition 用于后端下载。在我们的业务中,几乎都是这种情况,download 属性实际上并没有起到作用,而且它还对某个浏览器有兼容性问题,所以我们的解决方案就是去掉 download 属性设置。

新的疑问

不知道当你看完上面的内容,心中是不是得到了一个结论,让后端在 HTTP 请求结果中设置正确的 Content-Disposition 头就可以实现下载了?请接着往下看...

我们知道常见的下载方式有:

  1. 上文提到的 downloadFile 的方式,即动态创建 a 标签,模拟点击的方式进行下载
  2. window.open() 的方式
  3. form 表单提交的方式

有想过为什么这些方式可以吗?

回答:

文件下载其实是浏览器的行为,我们必须要用一个浏览器上下文去承载响应。这就可以理解上面几种方式了。a 标签点击,window.open 都会打开一个页面。

form 提交呢?

我们想想表单提交之后返回了啥?它有一个 target 的属性,表示在提交表单后,在哪里展示响应信息,可以设置 _self, _blank, _parent, _top,默认值是 _self,表示在相同的浏览器上下文中加载响应。那就可以理解 form 提交为啥能支持下载文件了。

栗子

可在下面的代码仓库中查看相关栗子,加深理解二者对文件下载以及文件名称的影响。

https://github.com/superdc/download-file-demo​github.com
基于SSM框架的智能家政保洁预约系统,是一个旨在提高家政保洁服务预约效率和管理水平的平台。该系统通过集成现代信息技术,为家政公司、家政服务人员和消费者提供了一个便捷的在线预约和管理系统。 系统的主要功能包括: 1. **用户管理**:允许消费者注册、登录,并管理他们的个人资料和预约历史。 2. **家政人员管理**:家政服务人员可以注册并更新自己的个人信息、服务类别和服务时间。 3. **服务预约**:消费者可以浏览不同的家政服务选项,选择合适的服务人员,并在线预约服务。 4. **订单管理**:系统支持订单的创建、跟踪和管理,包括订单的确认、完成和评价。 5. **评价系统**:消费者可以在家政服务完成后对服务进行评价,帮助提高服务质量和透明度。 6. **后台管理**:管理员可以管理用户、家政人员信息、服务类别、预约订单以及处理用户反馈。 系统采用Java语言开发,使用MySQL数据库进行数据存储,通过B/S架构实现用户与服务的在线交互。系统设计考虑了不同用户角色的需求,包括管理员、家政服务人员和普通用户,每个角色都有相应的权限和功能。此外,系统还采用了软件组件化、精化体系结构、分离逻辑和数据等方法,以便于未来的系统升级和维护。 智能家政保洁预约系统通过提供一个集的平台,不仅方便了消费者的预约和管理,也为家政服务人员提供了一个展示和推广自己服务的机会。同时,系统的后台管理功能为家政公司提供了强大的数据支持和决策辅助,有助于提高服务质量和管理效率。该系统的设计与实现,标志着家政保洁服务向现代化和网络化的转型,为管理决策和控制提供保障,是行业发展的重要里程碑。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值