前端下载文件的方式

前端,下载,文件,方式 · 浏览次数 : 1724

小编点评

## 总结 前端下载文件主要分为两种方式: 1. **直接返回网络地址的方式**:适用于静态文件,例如图片和视频等。 2. **返回文件流的方式**:适用于动态文件,例如根据前端选择,导出不同的统计结果等。 **关键问题及解决方案:** 1. **responseType问题**:默认值为 `json` 或 `text`,但二进制文件下载失败,原因是 `Blob` 的默认类型是 `blob`,而文本文件的类型不是 `blob`,导致下载失败。解决方案是明确设置 `responseType` 为 `blob`。 2. **下载文件类型问题**:由于 `RestPost<T>` 需要设置 `responseType` 为 `blob`,但文本文件的 `responseType` 应该设置为 `text`,因为下载完成后,要读取到的内容不是 JSON 格式的,而是文本格式。解决方案是设置 `responseType` 为 `blob`。 ## 其他建议 1. 可以根据实际情况进行参数设置,例如指定文件长度等。 2. 可以添加下载完成后,提示用户打开文件等操作。 3. 可以使用进度条等辅助提示,让用户了解下载进度。

正文

概要

在前端下载文件是个很通用的需求,一般后端会提供下载的方式有两种:

  1. 直接返回文件的网络地址(一般用在静态文件上,比如图片以及各种音视频资源等)
  2. 返回文件流(一般用在动态文件上,比如根据前端选择,导出不同的统计结果 excel 等)

第一种方式比较简单,但是使用场景有限。
第二种方式通用性更好,最近再使用 antd 开发的过程中,下载文件部分折腾了一下午,于是将关键的部分和遇到的一些问题整理如下。

前端核心代码

我的前端是基于 antd pro 开发的,这里不在详细介绍 antd pro 相关的内容,只说明下封装的下载函数:

import { request } from "umi";

// 这是我在项目中封装的下载函数,有2个参数:
// 一个是文件的id,用来给后端API搜索文件用的
// 一个是文件名filename,这个给前端用的,下载时,默认保存的文件名
export async function DownloadFile(id: string, filename: string) {
  return RestGet<BlobPart>(`/api/v1/file/download/${id}`, "blob").then(
    (res) => {
      let url = URL.createObjectURL(new Blob([res], { type: "octet/stream" }));
      let a = document.createElement("a");
      a.href = url;
      a.download = filename;
      a.click();
      URL.revokeObjectURL(url);
    }
  );
}

// GET 方式请求后端API
export async function RestGet<T>(
  url: string,
  responseType: "json" | "blob" = "json"
) {
  return request<T>(url, {
    method: "GET",
    headers: {
      "Content-Type": "application/json",
    },
    responseType: responseType,
  });
}

// POST 方式请求后端API
export async function RestPost<T>(
  url: string,
  body: any,
  responseType: "json" | "blob" = "json"
) {
  return request<T>(url, {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
    },
    data: body,
    responseType: responseType,
  });
}

这个下载函数本质就是创建一个 <a> 元素,然后模拟点击此 <a> 元素来完成下载。
对于 DownloadFile函数,我是根据自己的需要封装的,不一定非得是这两个参数,可以根据自己的后端 API 来定制需要传入的参数。

将下载封装成函数之后看,前端就可以通过一个按钮来下载文件了,比如:

<Button
  type="link"
  key="download"
  icon={<DownloadOutlined />}
  onClick={() =>
    DownloadFile(item.video_file_id as string, (item.name as string) + ".mp4")
  }
>
  下载
</Button>

我这里是 GET 方式下载文件的,如果参数比较多且复杂的话,也可以使用 POST 方式。
只要把 DownloadFileRestGet<T>改成 RestPost<T>,并调整相应的参数即可。

遇到的问题

调试其中的下载方式就不提了,遇到的最大困难,搜索半天也没什么人提到的就是请求中的 responseType问题。

刚开始,我没有设置 responseType,默认值好像是 json或者 text
测试时发现,下载文本类型的文件没有问题,但是下载二进制文件的话,比如视频或者图片,下载之后总是无法正常打开,前后端也没有任何错误提示。

折腾了半天,才试出 responseType传入 blob的话,二进制文件才能正常下载。
而且发现,设置成 blob的话,文本类型的文件也能正常下载打开。

与前端下载文件的方式相似的内容:

前端下载文件的方式

概要 在前端下载文件是个很通用的需求,一般后端会提供下载的方式有两种: 直接返回文件的网络地址(一般用在静态文件上,比如图片以及各种音视频资源等) 返回文件流(一般用在动态文件上,比如根据前端选择,导出不同的统计结果 excel 等) 第一种方式比较简单,但是使用场景有限。第二种方式通用性更好,最近

想让你的工作轻松高效吗?揭秘Java + React导出Excel/PDF的绝妙技巧!

**前言** 在B/S架构中,服务端导出是一种高效的方式。它将导出的逻辑放在服务端,前端仅需发起请求即可。通过在服务端完成导出后,前端再下载文件完成整个导出过程。服务端导出具有许多优点,如数据安全、适用于大规模数据场景以及不受前端性能影响等。 本文将使用前端框架React和服务端框架Spring B

Java与React轻松导出Excel/PDF数据

前言 在B/S架构中,服务端导出是一种高效的方式。它将导出的逻辑放在服务端,前端仅需发起请求即可。通过在服务端完成导出后,前端再下载文件完成整个导出过程。服务端导出具有许多优点,如数据安全、适用于大规模数据场景以及不受前端性能影响等。 本文将使用前端框架React和服务端框架Spring Boot搭

Chrome 103支持使用本地字体,纯前端导出PDF优化

在前端导出PDF,解决中文乱码一直是一个头疼的问题。要解决这个问题,需要将ttf等字体文件内容注册到页面PDF生成器中。但是之前网页是没有权限直接获取客户机器字体文件,这时就需要从服务器下载字体文件或者提示用户选择字体文件上传到页面。对于动辄数十兆(M)的中文字体文件,网络不好时并不是一个好的解决方

C#开源且免费的Windows桌面快速预览神器 - QuickLook

前言 今天给大家推荐一款由C#开源且免费的Windows桌面快速预览神器:QuickLook。 工具介绍 QuickLook是一款在Windows操作系统上的实用工具,它提供了一种快速预览文件内容的方式。通过使用QuickLook,用户可以在不打开文件的情况下,直接在文件资源管理器中快速查看文件的内

前端文件上传的几种交互造轮子

前端文件上传本来是一个常规交互操作,没什么特殊性可言,但是最近在做文件上传,需要实现截图粘贴上传,去找了下有没有什么好用的组件,网上提供的方法有,但是没找完整的组件来支持cv上传,经过了解发现可以用剪贴板功能让自己的cv实现文件上传,于是自己就整合了目前几种文件上传的交互方式,码了一个支持cv的vue3文件上传组件(造个轮子)。

EndNote里参考文献的期刊名显示错误怎么办?

本文介绍EndNote文献管理软件导入文献引用时,期刊名称带有%J前缀从而不能正常显示的解决方法。 前期的文章中,我们多次介绍了文献管理软件EndNote的具体使用方法与技巧。而在使用EndNote软件时,我们经常下载.enw等格式的文献数据库导入文件,从而在EndNote软件中导入我们的参考文献信

redux-saga原理

前言 工作中使用了redux-saga这个redux中间件,如果不明白内部原理使用起来会让人摸不着头脑,阅读源码后特意对其原理做下总结。 redux的特点 一个标准、管理应用副作用的redux中间件 实现切面编程方式 声明式的编写方式 订阅发布的设计模式 优点: 把异步操作转移到单独 saga文件中

前端配置化表单组件设计方法

前端开发中涉及表单的页面非常多,看似功能简单,开发快速,实则占去了很大一部分时间。当某个表单包含元素过多时还会导致html代码过多,vue文件过大。从而不容易查找、修改和维护。为了提高开发效率及降低维护成本,下面介绍表单配置化组件的封装原理与封装方法。

解决因对EFCore执行SQL方法不熟练而引起的问题

前言 本文测试环境:VS2022+.Net7+MySQL 因为我想要实现使用EFCore去执行sql文件,所以就用到了方法ExecuteSqlAsync,然后就产生了下面的问题,首先因为方法接收的参数是一个FormattableString,它又是一个抽象类,所以我就瞎测试使用下面方式构建 usin