H5中的文档和视频下载国内的手机浏览器有很多,再加上各个品牌自带的浏览器,以及Android上的chrome,每种浏览器
国内的手机浏览器有很多,再加上各个品牌自带的浏览器,以及Android上的chrome,每种浏览器的表现都不尽相同。如果想要在H5中,实现文档和视频的下载,应该怎么做呢?
需求来啦
我们业务线有多种设备,在运营后台可以上传每种设备的介绍文档、使用文档、配套视频等文件(我们使用的是腾讯云,上传到存储桶中)。官网上有一个指向app下载和这些文件的二维码(实际就是一个H5地址,页面上有下载app的按钮,也可进入各个设备的文档、视频列表页)。现在想在列表项后面,加一个下载图标,用户可以把文件下载到本地。
1. a标签+download
第一反应这不就是<a href="文件地址" download="文件名">icon-download</a>
嘛,正好我们是上传到腾讯云存储桶的(允许跨域配置过了),返回的就是文件的访问地址,开整。
本地开发和测试的时候,肯定还是在PC端,试了下,文档没啥问题(docx),视频不行(mp4)。首先我们要知道,a标签的download属性是干嘛的:假如说一个文件,浏览器可以直接打开,比如图片(通过请求头中Content-Type中的MIME类型
,识别数据类型,做对应处理),浏览器的默认行为是打开这个文件;download就是告诉浏览器,我的目的是下载,你别打开,直接下载就行了。但是,假如这种文件类型,浏览器本身就打不开,那它的默认行为自然就是下载。这其实和使用window.open
方式是一样的。
为啥视频不行呢,难道是兼容性问题?我就去看了下caniuse。瞥了一眼,感觉这兼容性应该没啥问题啊。
然后我看到下面的
Known issues(3)
,原来download真的有问题:跨域限制
我们这些文件都是在腾讯云上,域名肯定是不一样的,那只能用其他方法了。
2.fetch+URL.createObjectURL+a标签
URL
接口的 createObjectURL()
静态方法创建一个用于表示参数中给出的对象的 URL 的字符串。
URL 的生命周期与其创建时所在窗口的 document
绑定在一起。新对象 URL 代表指定的 File
对象或 Blob
对象。
要释放对象 URL,请调用 revokeObjectURL()
createObjectURL()
这个方法相信大家都用过,通常项目中需要下载一些业务数据的时候,应该都是用的这个方法,把后台传过来的blob
,构建出来一个地址,然后用a标签下载
。
fetch(fileURL, {mode:'cors'}).then(async res => {
const blob = await res.blob()
const downloadURL = URL.createObjectURL(blob)
// 构建a标签
const a = document.createElement('a')
a.setAttribute('href', downloadURL)
a.setAttribute('download', filename)
a.click()
URL.revokeObjectURL(downloadURL)
})
用了这种方式,试了下,都可以下载了,但是在手机浏览器上,就不行了。 我用小米自带浏览器,文档和视频都可以;用qq浏览器,文档可以,视频会生成下载任务,但是不会去下载;用oppo自带浏览器,文档和视频都只会生成下载任务,不会去下载;其他浏览器也都大差不差,下载任务可以生成,但是不会下载;有的是只能下载一部分,进度就停了。chrome for Android也可以,safari有点记不得了。
- 这个不清楚是不是手机浏览器有什么限制,如果有jy知道,希望回复告知!
3.Content-Disposition: attachment;filename="xxx"
这个之前还真不清楚,问了下同组的同事。正好用得是腾讯云,看了下腾讯云的文档对象存储-下载对象,看到了里面的一个例子:
// 摘抄自例子,实际使用过程中都是使用临时密钥
cos.getObjectUrl({
Bucket: config.Bucket,
Region: config.Region,
Key: item.Key,
}, function(err, data) {
if (err) return console.log(err);
setTimeout(() => {
var downloadUrl = data.Url + (data.Url.indexOf('?') > -1 ? '&' : '?') +
'response-content-disposition=attachment;filename=xxx'; // 补充强制下载的参数
window.open(downloadUrl);
// 这里是新窗口打开 url,如果需要在当前窗口打开,可以使用隐藏的 iframe 下载,
// 或使用 a 标签 download 属性协助下载
}, 500);
})
腾讯云提供了一个通过在地址后面拼接参数,可以使响应头上带上content-disposition: attachment
的方法(上传文件时返回的地址,直接拼接是不可以的,没有用,必须得调用getObjedctUrl方法返回的地址才行,腾讯云做了限制应该)
使用这个方法,绝大部分浏览器都可以了,文档、视频都能正常下载,但是百度浏览器不行,这就不知道用什么法子了。jy们有什么建议没
总结
Content-Disposition: attachment
适用性最广,借助浏览器的流式传输,但是要后端或运维进行改造a标签download
不跨域的情况下,最简单请求+URL.createObjectURL+动态a标签
手机浏览器上问题比较大,PC端没问题,但是会增加内存占用,需要及时释放,并且createObjectURL随文件增大时间增加(这玩意是同步的)
后记 由于我们需要调接口来获取腾讯云临时密钥,这个页面访问又不需要登录,后端认为有安全隐患,不能开白名单,所以最终说服产品,文档和视频就叫用户直接在浏览器上看就完事了,反正手机浏览器都支持;某些可以通过createObjectURL下载的浏览器,前端判断下,再显示下载图标😂。所以说,说服产品最重要💪
转载自:https://juejin.cn/post/7411480128528433206