前端下载
对于浏览器来说,部分文件是可以预览的,如 png, jpeg, gif,一般来说,浏览器打开这些文件时,不会自动下载;只有在打开比如 zip 等不支持预览的文件时,才会自动下载。
下载的方式又分为 a 标签的 download 和响应头 content-disposition.
这里分别讨论不同场景浏览器会如何处理,以及两种下载方式的优先级。
1. 不下载
zip | png | |
---|---|---|
同源 | 下载 | 预览 |
跨域 | 下载 | 预览 |
2. a 标签 download
需要注意的是,对于跨域的链接,a 标签 download 属性是无效的,相当于没设置这个属性!
简单用法
<a href="/path/to/filename" download="filename">点击下载</a>
JS 版本
const downloadByUrl = (url: string, filename: string) => {
if (!url) {
throw new Error('当前没有下载链接')
}
const a = document.createElement('a')
a.style.display = 'none'
a.href = url
a.download = filename
a.rel = 'noopener noreferrer'
document.body.append(a)
a.click()
document.body.removeChild(a)
}
直接将下载链接添加 a 标签 href 属性的问题在于它并不能携带更多信息,比如请求头。因此大多数时候我们会借助 blob 进行类型转换再下载
function download(imageUrl: string, filename: string) {
return fetch(imageUrl)
.then((response) => response.blob())
.then((blob) => {
const downloadUrl = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = downloadUrl
a.download = filename
document.body.appendChild(a)
a.click()
// 清理工作
document.body.removeChild(a)
URL.revokeObjectURL(downloadUrl)
})
.catch((error) => console.error('Error downloading the image:', error))
}
浏览器处理
zip | png | |
---|---|---|
同源 | 下载 | 下载 |
跨域 | 下载 | 预览 |
3. Content-Disposition
信息
MDN: 在常规的 HTTP 应答中,Content-Disposition 响应标头指示回复的内容该以何种形式展示,是以内联的形式(即网页或者页面的一部分),还是以附件的形式下载并保存到本地
响应示例
Content-Disposition: inline
Content-Disposition: attachment; filename="filename.jpg"
浏览器处理
zip | png | |
---|---|---|
同源 | 下载 | 下载 |
跨域 | 下载 | 下载 |
4. 优先级
-
inline 的优先级和 download 怎么样?
download > inline。可能不算优先级更高?理解成只要任意方式设置为去下载,就去下载文件!
-
download 和 attachment filename 哪个优先级更高?
attachment
5. 处理方式总结
zip | png | |
---|---|---|
不下载 | ||
同源 | 下载 | 预览 |
跨域 | 下载 | 预览 |
download | ||
同源 | 下载 | 下载 |
跨域 | 下载 | 预览 |
content-disposition | ||
同源 | 下载 | 下载 |
跨域 | 下载 | 下载 |