前端实现文件下载(a标签实现文件下载 避免直接打开问题)

您所在的位置:网站首页 前端实现下载到指定文件夹 前端实现文件下载(a标签实现文件下载 避免直接打开问题)

前端实现文件下载(a标签实现文件下载 避免直接打开问题)

2023-08-04 18:36| 来源: 网络整理| 查看: 265

先说结论 所有情况通用的方式: 后端设置下载请求的响应头 Content-Disposition: attachment; filename="filename.jpg" attachment 表示让浏览器强制下载 filename 用于设置下载弹出框里预填的文件名 非跨域情况下 给a标签加上 download 属性,如 download 里写文件名 注意后缀 (值非必填) 通过请求解决跨域问题 动态创建a标签通过blob形式下载 具体看下面解析

文件下载通常有以下方式

下载 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” 优先于 优先于 url最后一节 http://localhost:8087/upload/文件名.png



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3