文件上传下载是项目中经常会遇到的常规功能,例如静态资源下载、数据导出等等。本文总结了三种针文件下载的方法。

前端实现下载的原理一般是基于a标签下载。浏览器内部提供了钩子,而且在H5当中a标签新增了download属性。浏览器支持,当该属性的链接被点击时,浏览器会以下载文件的方式下载href的属性上的链接 这就是所谓的“钩子”。

1.文件流方式

如果后台服务器无可供下载的静态资源,一般使用文件流方式下载,不至于过多占用服务器资源,一般常用于动态的导出数据等情景。

后端返回response:
image.png

代码实现

  1. export function PostDownload (url, data) {
  2. return new Promise((resolve, reject) => {
  3. Request
  4. .post(url, data, {
  5. responseType: 'blob' // 必需
  6. })
  7. .then((res) => {
  8. if (res && res.status == 200) {
  9. reject(new Error('Download Failed'))
  10. } else {
  11. // 对后端返回的文件流处理,res.data即后端返回的文件流如上图
  12. const blob = new Blob([res.data])
  13. let filename = data.filename || `${new Date() - 0}.xlsx`;
  14. try {
  15. filename = decodeURI(res.headers['content-disposition'].split(';')[1].split('filename=')[1]);
  16. } catch (e) {
  17. console.log(e)
  18. }
  19. if (typeof window.navigator.msSaveBlob !== 'undefined') {
  20. window.navigator.msSaveBlob(blob, filename);
  21. } else {
  22. const url: any = window.URL.createObjectURL(blob);
  23. const link = document.createElement('a');
  24. link.style.display = 'none';
  25. link.href = url;
  26. link.setAttribute('download', filename);
  27. document.body.appendChild(link);
  28. link.click();
  29. URL.revokeObjectURL(url.href);
  30. document.body.removeChild(link);
  31. resolve()
  32. }
  33. }
  34. })
  35. .catch(() => {
  36. Message.error({
  37. message: 'Download Failed',
  38. duration: 2000
  39. })
  40. })
  41. })
  42. }

注意事项

1)设置响应类型blob

请求头中需设置responseType:'blob',否则下载的文件将解析失败无法打开;

接口返回的完整的数据结构:

image.png

2)filename的获取方式

注意:在响应头中,一定要后端暴露给客户端即在Access-Control-Expose-Headers里列出来,否则即使服务器在协议回包里加了该字段,客户端也只能看到无法在代码中获取到它的值。

image.png

2.url下载(GET方式下载)

下载的文件存储在静态资源服务器中,可以使用这种方法。后端直接返回对应资源服务器的资源url,前端直接window.location.href方式获取即可。

  1. window.location.href="http://www.域名/template.xlsx(文件名)";
  2. window.open(url);

3.无API浏览器直接下载

将静态资源文件直接放于 public 目录下,打包时 public 文件不会被编译。

注意:静态资源的路径,在 public 文件夹下路径是/文件名

  1. <a class="download-file" href="/file.xlsx" download="模板.xlsx">下载模板文件</a>

或者使用非 a 标签的按钮下载:

  1. /*
  2. @param {string} url 静态资源url
  3. @param {string} filename 静态资源文件名(可选)
  4. @param {string} target
  5. */
  6. export const fileUrlHandled = ({ url, filename, target }) => {
  7. const downloadElement = document.createElement('a')
  8. downloadElement.style.display = 'none'
  9. downloadElement.href = url
  10. if (target) {
  11. downloadElement.target = '_blank'
  12. }
  13. downloadElement.rel = 'noopener noreferrer'
  14. if (filename) {
  15. downloadElement.download = filename
  16. }
  17. document.body.appendChild(downloadElement)
  18. downloadElement.click()
  19. document.body.removeChild(downloadElement)
  20. }

缺点:文件名不可控。

最后

以上三种文件下载方式,是工作中不同情境所用方法的总结,如果对你有所帮助的话,帮忙点赞呀👍,你的阅读和点赞是我继续下一篇的动力,感谢!

本文著作权归作者翻雪所有,转载请注明出处。