前端实现文件下载
浏览器打开链接后默认会尝试预览该文件,浏览器下载的本质是告诉浏览器将该资源提供给用户进行保存 两种情况浏览器会主动将一个链接对应的资源进行下载
- 响应
Content-Disposition
为attachment
显示的告诉浏览器进行资源的下载 - 响应
Content-Type
为浏览器不支持预览的类型/缺少该字段但浏览器判断出该文件不支持预览
手动实现文件下载需要利用浏览器的这种行为(本质上就是打开文件的下载链接),可以有几种方式:
form
表单提交- 一种古老的文件下载方式
- 核心是当需要进行下载时动态生成一个表单,利用表单提交的功能来实现文件的下载
javascriptfunction downloadFile (url) { const form = document.createElement('form') form.action = url form.method = 'get' form.style.display = 'none' document.body.appendChild(form) form.submit(); // 提交表单,下载文件 document.body.removeChild(form) }
window.open
/location.href
a
链接跳转
这几种方式都可以让页面跳转到下载链接实现文件的下载,并且可以发现,如果是在当前 tab 页面跳转触发下载行为,地址栏不会改变 缺点这几种方式当然也一样:
- 当跳转的下载链接缺少
Content-Disposition
时只能下载浏览器无法预览的文件类型,浏览器可预览的文件类型会跳转为预览 - 无法携带多余的 HTTP header,在一些鉴权的场景无法使用
a 标签 download
HTML5 新增download
属性可以让浏览器直接下载所有类型文件,无需依赖Content-Disposition
html<a href="example.jpg" download>点击下载</a> <!-- 重命名下载文件 --> <a href="example.jpg" download="test">点击下载</a>
download
仅对同源 URL 或blob:
、data:
协议起作用
- 对于跨域链接
download
会失效,浏览器依旧会优先进行文件的预览而不是下载 - 如果非要进行跨域下载,可以先将数据转换为
blob:
或data:
再进行下载
blob 和 dataURL
对于blob:
或data:
协议的下载
- 获取二进制数据并转化为
Blob
,使用URL.createObjectUrl
生成地址 / 获取二进制数据并转化为 Data URL - 借助
a
标签进行下载
javascriptfunction downloadFile(url, name) { const a = document.createElement('a') a.style.display = 'none' a.href = url a.download = name; document.body.appendChild(a) a.click() document.body.removeChild(a) } function fetchData() { return new Promise((resolve) => { const xhr = new XMLHttpRequest() xhr.open('get', path) xhr.responseType = 'blob' xhr.send() xhr.onload = function () { resolve(this.response) }; }) } // blob const response = await fetchData() const url = URL.createObjectURL(this.response) downloadFile(url, 'example.txt') URL.revokeObjectURL(url) // data url const response = await fetchData() const fileReader = new FileReader() fileReader.readAsDataURL(response) fileReader.onload = function () { downloadFile(this.result, 'example.txt') }
这两种方式存在的问题也都一样
- 需要先将文件请求到本次才进行下载,具有两次下载
- 大文件会占用大量内存,这可能导致性能问题,尤其是在移动设备或资源受限的环境中
优点是
- 可以在客户端动态生成文件内容,不一定需要再服务器上生成或存储文件
- 可以在需要鉴权的环境下进行文件的下载
Content-Disposition
Content-Disposition
HTTP 响应头指示客户端以何种形式显示响应内容
基本的格式:
httpContent-Disposition: <disposition-type>; [filename=<filename>]
disposition-type
表示处理方式
attachment
: 告诉客户端应该将文件作为附件下载,如果后面存在filename
,会作为下载的文件名inline
: 指明直接展示资源,当然当浏览器不支持改类型的资源是依旧会提示下载- 其他自定义值: 可以是其他处理方式,具体效果取决于用户代理的支持情况
优先级
attachiment
的优先级是最高的,无论使用何种方式跳转链接,都会实现文件下载。
当 disposition-type
值为inline
时,download
会优先于 inline
实现文件下载
参考