资讯专栏INFORMATION COLUMN

前端实现文件下载

mylxsw / 2658人阅读

摘要:之前写了一篇前端实现图片下载,大部分场景下,文件下载都可以按照这个思路来实现。其实可以和后台约定返回内容,前端通过监听的内容实现监听。纵观源码,主要实现上传,可借鉴用于下载的方案并没有发现对请求的状态进行监听。

之前写了一篇《前端实现图片下载》,大部分场景下,文件下载都可以按照这个思路来实现。

但是,最近遇到了一个新的需求——POST 下载。服务端只支持 POST 请求,而上一篇文章中涉及的大部分场景都是 GET 请求。

服务端实现

以 Node + Koa2 实现为例,服务端返回 excel 文件流

</>复制代码

  1. const fs = require("fs")
  2. const path = require("path")
  3. module.exports = ctx => {
  4. ctx.set("Content-Type", "application/vnd.ms-excel")
  5. ctx.set("Content-Disposition", "attachment; filename=download.xlsx")
  6. ctx.body = fs.createReadStream(path.resolve(__dirname, "./download.xlsx"))
  7. }
兼容性好的老方案

经典的、兼容性好的方案可以通过构建 Form 表单来实现

</>复制代码

  1. let uuidIndex = 0
  2. export default (url, params, method = "post") => {
  3. const uuid = `TMP_FRAME_NAME__${uuidIndex++}`
  4. const iframe = document.createElement("iframe")
  5. iframe.name = uuid
  6. iframe.style = "display:none"
  7. // 无论响应成功失败,都会调用 onload
  8. // iframe.onload = success
  9. // iframe.onerror = fail
  10. document.body.appendChild(iframe)
  11. const form = document.createElement("form")
  12. form.action = url
  13. form.method = method
  14. form.target = uuid
  15. form.style = "display:none"
  16. form.enctype = "application/x-www-form-urlencoded"
  17. document.body.appendChild(form)
  18. if (params) {
  19. Object.keys(params).forEach(key => {
  20. const v = params[key]
  21. if (v !== undefined) {
  22. const input = document.createElement("input")
  23. input.type = "hidden"
  24. input.name = key
  25. input.value = v
  26. form.appendChild(input)
  27. }
  28. })
  29. }
  30. form.submit()
  31. document.body.removeChild(form)
  32. document.body.removeChild(iframe)
  33. }
寻找新方案

产品提了一个需求,下载成功要提示,下载失败也要提示。那么问题来了,上面的老方案,不太好监听这次操作是正常还是异常。(其实可以和后台约定返回内容,前端通过监听 iframe 的内容实现监听。)

插曲

有个 jQuery 插件 jquery.form.js API 中提供了对成功和失败的回调。纵观源码,主要实现 form 上传,可借鉴用于下载的方案并没有发现对请求的状态进行监听。

正题

在经历了以上插曲后,找到一种新的方案。

在新方案中,使用了一些 HTML5 的 API,例如 Blob。所以,兼容性需要 IE 10+ 。

</>复制代码

  1. function download(url, name) {
  2. const aLink = document.createElement("a")
  3. aLink.download = name
  4. aLink.href = url
  5. aLink.dispatchEvent(new MouseEvent("click", {}))
  6. }
  7. export default (data, name, type) => {
  8. const blob = new Blob([data], { type })
  9. const url = URL.createObjectURL(blob)
  10. download(url, name)
  11. }
demo 一枚

</>复制代码

</>复制代码

  1. import axios from "axios"
  2. // 上面的新方案
  3. import download from "./download"
  4. document.getElementById("button").addEventListener("click", () => {
  5. axios.post("/download", null, {
  6. // 记得设置为成以 buffer 格式读取
  7. responseType: "arraybuffer"
  8. })
  9. .then((res) => {
  10. // 从响应头里面读取名字,当然,可以自定义
  11. const name = res.headers["content-disposition"].replace(/.*filename=/, "")
  12. download(res.data, name, "application/vnd.ms-excel")
  13. })
  14. .catch((error) => {
  15. console.log(error)
  16. })
  17. })
吐槽

segmentfault 网站编辑器编辑 markdown 对 js 代码块的解析有 bug,带了箭头函数 // 注释就失效了。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/96631.html

相关文章

  • node实现文件下载不得不说的那些事儿

    摘要:如果像本例中这样的场景会遇到这样一个问题,详见链接当请求参数过长或为了安全,就需要用到下载。写到这里自己都忍不住想锤自己,给自己挖坑不说,这样来回请求下载,流量,真的是败家。 这几天一直在做远程文件下载的事,现在总算有了解决,特来记录一下踩过的坑和想揍自己的心 需求 应用场景是这样的,底层逻辑数据请求接口是由Java写的,也就是说原始文件存在Java服务端,返回时有加密措施 由于工作...

    Coly 评论0 收藏0
  • 简谈文件下载的三种方式

    摘要:一前言本文章将以报表下载为例,给大家介绍三种文件下载的方式。通过二进制数据流的方式下载这种方式是我目前采用的方式,用于处理报表下载。缺点对于数据量不大的文件,这种方式是可行的。 一、前言 本文章将以excel报表下载为例,给大家介绍三种文件下载的方式。 原文地址:简谈文件下载的三种方式 | Rychou 二、正文 1. 通过服务器文件地址下载 这是最常见的文件下载方式,大多数网站的音频...

    lsxiao 评论0 收藏0
  • 简谈文件下载的三种方式

    摘要:一前言本文章将以报表下载为例,给大家介绍三种文件下载的方式。通过二进制数据流的方式下载这种方式是我目前采用的方式,用于处理报表下载。缺点对于数据量不大的文件,这种方式是可行的。 一、前言 本文章将以excel报表下载为例,给大家介绍三种文件下载的方式。 原文地址:简谈文件下载的三种方式 | Rychou 二、正文 1. 通过服务器文件地址下载 这是最常见的文件下载方式,大多数网站的音频...

    2i18ns 评论0 收藏0
  • 实现前后端分离的心得

    摘要:实现前后端分离的心得对目前的来说,前后端分离已经变得越来越流行了,越来越多的企业网站都开始往这个方向靠拢。前后端工作分配不均。 实现前后端分离的心得 对目前的web来说,前后端分离已经变得越来越流行了,越来越多的企业/网站都开始往这个方向靠拢。那么,为什么要选择前后端分离呢?前后端分离对实际开发有什么好处呢? 为什么选择前后端分离 在以前传统的网站开发中,前端一般扮演的只是切图的工作...

    zilu 评论0 收藏0
  • 前端UI组件复用工具

    摘要:代码复用总是程序员喜闻乐见的,前端组件化的最终目的就是复用,今天我们就将深入探讨如何实现组件的复用。 懒是第一生产力。 代码复用总是程序员喜闻乐见的,前端组件化的最终目的就是复用,今天我们就将深入探讨如何实现UI组件的复用。 通常我们所说的组件往往是包含业务逻辑的前端组件,而这类组件实际上很难实现广义上的复用,顶多能在同一条业务线上复用一下,但UI组件就不一样了,没有了业务的约束,只在...

    xuxueli 评论0 收藏0

发表评论

0条评论

mylxsw

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<