前言
我们一般在浏览器看到的下载功能,基本是点击按钮就会触发浏览器的下载功能,将文件下载在本地。当作为码农的我们接到要求实现一个下载功能,我们该如何实现呢?
很多时候前端接收到下载需求,一般只要告诉对接的后端,后端处理就好了, 那么后端是如何处理的呢?
最近身边同事遇到文件无法下载的问题,在帮忙解决的时候发现, 前后端两位竟然都不知道该如何处理,在解决问题的同时顺便整理一波。
文件下载实现方式
1.a标签使用download
下载内容
后端直接提供url的文件
使用方式:
直接 <a href="path" download="filename">文件下载</a>
或者通过js触发,创建a标签执行下载
注意事项:
下载资源必须同源,无法跨域,这块被坑了很久,网上搜的中文资料都没有提及到这块,跨域的使用属性只会打开图片,在标准文献上才有提示明确提示
同时存在兼容性,只能兼容chrome、firefox,同时txt、png、jpg、html等能够直接打开的在firefox下面无法生效
2.将图片等资源转成base64、blob下载
备注
解决firefox部分版本无法直接下载的问题, 主要还是依赖a标签download属性,具体不展开细讲,感兴趣可以自己深入去了解一下
使用方式
图片转成base64
txt、pdf等先转成base64 再转成blob
3.后端返回stream,前端通过blob下载
关键字:Blob, window.URL.createObjectURL
下面看一段例子, content只是测试的一段代码, 也可以是后端返回的steam进行处理
const content = { test: 'blob download', text: 'text download' }; const blobContent = new Blob( [JSON.stringify(content, null, 2)], {type : 'application/json'} ); const url = window.URL.createObjectURL(blobContent) downloadFileByBlob(url, 'content.json') function downloadByBlob(url, filename) { const link = document.createElement('a') link.download = filename link.style.display = 'none' link.href = blobUrl document.body.appendChild(link) link.click() document.body.removeChild(link) }
4.后端(node层)处理
文件访问增加response header
res.setHeader('Content-disposition', 'attachment; filename=xxxr.gz');
res.setHeader('Content-Type', 'application/octet-stream');
总结
- 上诉1、3、4是比较常用的下载方案,如果兼容性要求不大,一般同一个域下面的图片等资源通过方案1处理就好了,否则方案3、4。
- 通过方案4可以衍生出node层单独的解决方案,实现一个文件下载中间层提供下载,第三方资源都通过node层下载或者转发一次,修改response header。
- 上诉方案不是全部的下载方案,感兴趣的可以继续补充。