前端实现文件下载(a标签实现文件下载 避免直接打开问题)
先说结论
- 所有情况通用的方式: 后端设置下载请求的响应头
Content-Disposition: attachment; filename="filename.jpg"
attachment
表示让浏览器强制下载filename
用于设置下载弹出框里预填的文件名- 非跨域情况下 给a标签加上
download
属性,如<a href="url" download="xxx.png"></a>
download
里写文件名 注意后缀 (值非必填)- 通过请求解决跨域问题 动态创建a标签通过blob形式下载 具体看下面解析
文件下载通常有以下方式
<a href="http://localhost:8087/upload/user.png">下载</a>
a标签访问文件地址window.open('http://localhost:8087/upload/user.png')
打开文件地址- 后端提供一个接口
/api/download
通过接口返回文件流
浏览器通过请求头Content-Type
中的MIME类型(媒体类型,通常称为 Multipurpose Internet Mail Extensions 或 MIME 类型,如 :image/jpeg
application/pdf
)识别数据类型,对相应的数据做出相应处理,对于图像文本等浏览器可以直接打开的文件,默认处理方式就是打开,为了避免浏览器直接打开文件我们需要做一些处理;
方案一 a标签+download属性
当url
是同源(同域名、同协议、同端口号)时,这种情况用 a标签加download属性的方式即可,download属性指示浏览器该下载而不是打开该文件,同时该属性值即下载时的文件名;
方案二 后端设置下载请求的响应头 Content-Disposition
强制下载
这是最通用的一种方式 不受跨域和请求方式的影响
Content-Disposition: attachment; filename="filename.jpg"
想使用window.open
实现强制下载的可以用这种方式
在常规的 HTTP 应答中,该响应头的值表示对响应内容的展现形式
- inline 表示将响应内容作为页面的一部分进行展示
- attachment 表示将响应内容作为附件下载,大多数浏览器会呈现一个“保存为”的对话框
- filename(可选) 指定为保存框中预填的文件名
方案三 通过接口跨域请求,动态创建a标签,以blob形式下载
当接口请求的跨域问题已经解决时(如Nginx方式),可以直接通过请求的方式拿到文件流,将文件流转为blob格式,再通过a标签的download属性下载
// 用fetch发送请求
fetch('/upload/user.png').then((res) => {res.blob().then((blob) => {const blobUrl = window.URL.createObjectURL(blob);// 这里的文件名根据实际情况从响应头或者url里获取const filename = 'user.jpg';const a = document.createElement('a');a.href = blobUrl;a.download = filename;;a.click();window.URL.revokeObjectURL(blobUrl);});
});
上面通过原生fetch请求,动态生成一个a标签实现文件下载
res.blob()
该方法是Fetch API
的response对象方法,该方法将后端返回的文件流转换为返回blob的Promise;blob(Binary Large Object)
是一个二进制类型的对象,记录了原始数据信息URL.createObjectURL(blob)
该方法的返回值可以理解为一个 指向传入参数对象的url
可以通过该url
访问 参数传入的对象- 该方法需要注意的是,即便传入同一个对象作为参数,每次返回的
url
对象都是不同的 - 该
url
对象保存在内存中,只有在当前文档(document)被卸载时才会被清除,因此为了更好的性能,需要通过URL.revokeObjectURL(blobUrl)
主动释放
- 该方法需要注意的是,即便传入同一个对象作为参数,每次返回的
xhr
也可以实现,axios
也差不多,网上都有const xhr = new XMLHttpRequest(); xhr.open('GET', '/upload/user.png', true); xhr.responseType = 'blob'; xhr.onload = function() {if (this.status === 200) {const fileName = 'test.jpg';const blob = new Blob([this.response]);const blobUrl = window.URL.createObjectURL(blob);const a = document.createElement('a');a.href = blobUrl;a.download = fileName;a.click();window.URL.revokeObjectURL(blobUrl);} }; xhr.send();
注意
当用方案一二实现时,下载文件名优先取的是
Content-Disposition
的filename
而不是download
,而通过blob
的形式,文件名优先取的download
属性,如果都没有设置则取的url
最后一节;当通过接口的形式
fetch('/upload/downloadfile')
访问文件,又想保留浏览器的预览效果时,可以仅设置Content-Disposition
的filename
以指定预览时下载的文件名,否则浏览器会默认取url
最后一节,即downloadfile
为文件名,导致下载的文件无后缀无法打开window.open() 和 a标签
执行的是打开链接的操作,类似于将地址直接输入到浏览器中,相当于从一个域跳到另一个域,因此window.open('http://xxx')
可以访问而不会报跨域错误;而fetch/xhr
仅是从当前域发送请求,因此fetch('http://xxx')
会报跨域错误浏览器取下载时文件名的优先级是
Content-Disposition: filename=“文件名.png”
优先于<a download="文件名.png"></a>
优先于url最后一节 http://localhost:8087/upload/文件名.png
前端实现文件下载(a标签实现文件下载 避免直接打开问题)相关推荐
- 面试官:如何用a标签实现文件下载?(一文带你手撕知识点)
前言 大家好,今天给大家带来前端小知识:前端利用a标签实现文件(图片)下载,也就是教大家利用a标签或者是 window.open() 来实现下载功能. 文章目录 前言 常用方式 方法分析 代码实现 常 ...
- a 标签实现文件下载(解决打开的问题)
实现: a标签实现文件下载,是使用的相对路径下载. js代码 <a class="btn btn-success btn-sm" href="../docs/doc ...
- 逻辑(html)_文件下载(a标签的download属性)
目录 需求描述 实现过程 实现代码 问题 原因 解决 知识点 需求描述 需求:当点击按钮时,可以下载模板文件,下载地址如下 https://file2.clipworks.com/4c217acc09 ...
- 前端js实现字符串/图片/excel文件下载
在web开发中,如果你想让用户下载或者导出一个文件,应该怎么做呢? 传统的做法是在后端存储或者即时生成一个文件来提供下载功能,这样的优势是可以做权限控制.数据二次处理,但缺点是需要额外发起请求.增大服 ...
- 从零开始学前端 - 3. HTML 常用标签_2
作者: 她不美却常驻我心 博客地址: https://blog.csdn.net/qq_39506551 微信公众号:老王的前端分享 每篇文章纯属个人经验观点,如有错误疏漏欢迎指正.转载请附带作者信息 ...
- 前端之HTML常用标签
## 本资源由 itjc8.com 收集 --- typora-copy-images-to: media --- > 第01阶段.前端基础.HTML常用标签 ## 学习目标 - 理解: - ...
- 从零开始学前端 - 2. HTML常用标签_1
作者: 她不美却常驻我心 博客地址: https://blog.csdn.net/qq_39506551 微信公众号:老王的前端分享 每篇文章纯属个人经验观点,如有错误疏漏欢迎指正.转载请附带作者信息 ...
- 前端基础HTML-基础标签
前端基础HTML-基础标签 01-标题标签 <h1>1级标题</h1><h2>2级标题</h2><h3>3级标题</h3>< ...
- a 标签解决,新窗口打开跨域问题
a 标签解决,新窗口打开跨域问题 参考文章: (1)a 标签解决,新窗口打开跨域问题 (2)https://www.cnblogs.com/web-fusheng/p/10161955.html (3 ...
最新文章
- 文件管理器_苹果超强文件管理器,秒变安卓?
- GPIO代码使用流程(伪代码部分示例)
- .a 文件 和 so 文件
- php 正则 尖括号,php使用正则表达式提取字符串中尖括号、小括号、中括号、大括号中的字符...
- 对BottomTagFragment的理解
- 面试美团,面试官突然问我 Java “锁” ,我哭了
- dpkg检查某个应用是否已安装
- 支持二级汉字的 php 汉字助记码生成
- ensp华为防火墙及应用
- 决策树的特性及优缺点
- 夜天之书 #61 Maintainer 的标准
- IIS发布问题:HTTP错误404.17和404.2
- Java使用poi将list<Map>导出为表格
- 第4篇-DSP28069外设初始化2
- Mac安装win10出现的错误无法分区和Boot Camp分区不足
- 濮阳工学院2019计算机大赛二等奖,学习 | 第三届校长奖学金10名入围奖人选,看看都有谁?!...
- Property maxActive is not used in DBCP2, use maxTotal instead. maxTotal default value is 8. You have
- EBAZ4205矿卡控制卡
- NPDP产品经理小知识:知识产权管理
- mysql要求cpu主频还是核数_CPU主频和核数哪个更重要?电脑CPU到底主频高好还是多核好?...