资讯专栏INFORMATION COLUMN

前端实现文件下载

mylxsw / 2502人阅读

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

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

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

服务端实现

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

const fs = require("fs")
const path = require("path")

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

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

let uuidIndex = 0

export default (url, params, method = "post") => {
  const uuid = `TMP_FRAME_NAME__${uuidIndex++}`
  const iframe = document.createElement("iframe")
  iframe.name = uuid
  iframe.style = "display:none"
  // 无论响应成功失败,都会调用 onload
  // iframe.onload = success
  // iframe.onerror = fail
  document.body.appendChild(iframe)

  const form = document.createElement("form")
  form.action = url
  form.method = method
  form.target = uuid
  form.style = "display:none"
  form.enctype = "application/x-www-form-urlencoded"
  document.body.appendChild(form)

  if (params) {
    Object.keys(params).forEach(key => {
      const v = params[key]
      if (v !== undefined) {
        const input = document.createElement("input")
        input.type = "hidden"
        input.name = key
        input.value = v
        form.appendChild(input)
      }
    })
  }

  form.submit()
  document.body.removeChild(form)
  document.body.removeChild(iframe)
}
寻找新方案

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

插曲

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

正题

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

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

function download(url, name) {
  const aLink = document.createElement("a")
  aLink.download = name
  aLink.href = url
  aLink.dispatchEvent(new MouseEvent("click", {}))
}

export default (data, name, type) => {
  const blob = new Blob([data], { type })
  const url = URL.createObjectURL(blob)
  download(url, name)
}
demo 一枚
import axios from "axios"
// 上面的新方案
import download from "./download" 

document.getElementById("button").addEventListener("click", () => {
  axios.post("/download", null, {
    // 记得设置为成以 buffer 格式读取
    responseType: "arraybuffer"
  })
  .then((res) => {
    // 从响应头里面读取名字,当然,可以自定义
    const name = res.headers["content-disposition"].replace(/.*filename=/, "")
    download(res.data, name, "application/vnd.ms-excel")
  })
  .catch((error) => {
    console.log(error)
  })
})
吐槽

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元查看
<