如何实现下载

前言

我们一般在浏览器看到的下载功能,基本是点击按钮就会触发浏览器的下载功能,将文件下载在本地。当作为码农的我们接到要求实现一个下载功能,我们该如何实现呢?

很多时候前端接收到下载需求,一般只要告诉对接的后端,后端处理就好了, 那么后端是如何处理的呢?

最近身边同事遇到文件无法下载的问题,在帮忙解决的时候发现, 前后端两位竟然都不知道该如何处理,在解决问题的同时顺便整理一波。

文件下载实现方式

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。
  • 上诉方案不是全部的下载方案,感兴趣的可以继续补充。

暂无评论