前端同学们,你们知道如何应对后端通过响应体返回文件流吗?

简介: 今天给大家带来一个小知识,那就是分别从前端和后端同学的不同角度看他们是如何处理文件下载的,这个知识不光能有助于我们处理文件导出的需求,也能加深我们对HTTP协议的理解。

前言

今天说一个简单实用的小知识,在做一些管理系统时,我们往往会遇到导出Excel报表的需求,往往呢比较传统的方式就是后端借助POI工具包,或者是easyPOI,EasyExcel等更为简单,封装性更强的工具去做,使用这些工具往往就是将需要导出的文件以二进制流的方式通过HTTP请求的响应体传输。当然现在前端的功能也越来越强大,更为优雅的方式就是后端提供查询数据的接口,让前端同学去生成Excel文件,这样更能节约服务器资源,充分利用客户端的能力。

本篇文章主要是介绍传统的后端生成文件的形式,以及前端如何将后端返回的文件流进行下载。

后端出招

后端我们需要做的就是查询需要的数据,并且封装一个导出Excel文件的通用工具类,将一些导出信息传入工具类即可完成下载,本文我们以EasyExcel为例,这个工具很好用,导出的表头我们只需要通过注解配置即可。

下面便是我们需要封装的工具方法,我们只需要传入response、导出文件的文件名,数据,数据的DTO类,sheet的名称即可

这里我们需要关注几个点

  • response.setContentType("application/vnd.ms-excel");

    这个是指定网络文件的类型和网页的编码,决定浏览器将以什么形式、什么编码读取这个文件,这就是经常看到一些链接点击后是图片或者下载文件(每一种对应不同的文件扩展名))。

    • Content-Type: text/html; charset=utf-8: 网页格式(通过HTTP获取网页就是这种类型) .htm
    • Content-Type: application/json: JSON数据格式(我们经常写的前后端分离项目RestController的接口返回类型就是这个)
    • Content-Type: application/vnd.ms-excel: excel格式 .xls
    • Content-Type: application/pdf:pdf格式 .pdf
    • Content-Type: image/jpeg :jpg图片格式 .jpeg
    • ...
  • response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameEnCode + ".xlsx");

    Content-disposition 是 MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件。Content-disposition其实可以控制用户请求所得的内容存为一个文件的时候提供一个默认的文件名,文件直接在浏览器上显示或者在访问时弹出文件下载对话框。

    这里需要注意的是中文的文件名往往需要指定字符编码,防止乱码。

  • response.getOutputStream()

    以字节流输出,我们只需要将数据写入response.getOutputStream()的输出流中

    举例:response.getOutputStream().write("计算机".getBytes());

    /**
     * 导出 Excel
     * @param response  HttpServletResponse
     * @param fileName  文件名
     * @param list      数据
     * @param clazz   导出结构体
     * @param sheetName 导入文件的 sheet 名
     */
    public static <T> void writeExcel(HttpServletResponse response, String fileName, List<T> list, Class<T> clazz, String sheetName) throws IOException {
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileNameEnCode = URLEncoder.encode(fileName, "UTF-8").replaceAll("\+", "+");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileNameEnCode + ".xlsx");
        writeExcel(response.getOutputStream(), list, clazz, sheetName);
    }

后端我们只需要做这些操作即可,这样我们就可以通过HTTP向前端返回一个标准的携带文件的响应.

前端接招

我们前端同学在接收到这样请求,该如何去处理呢?

如果没有做过文件下载的前端同事可能一脸懵,怀疑后端给返回的这是什么鬼,满屏乱码,离谱

如果一个深入研究过HTTP的前端同学可能会对上述请求头的参数有所了解

通过HTTP的Content-Type和Content-disposition看出端倪,知道后端返回的这是一个Excel文件

那前端该如何处理呢?

上代码

export const download = (data) => {
  return request({
    url:'请求地址',
    method: 'post',
    responseType:'blob',
    data: data
  })
}
​
// 下载处理逻辑
const filename = res.headers["content-disposition"];
const blob = new Blob([res.data]);
var downloadElement = document.createElement("a");
// URL.createObjectURL()方法会根据传入的参数创建一个指向该参数对象的URL. 这个URL的生命仅存在于它被创建的这个文档里. 新的对象URL指向执行的File对象或者是Blob对象.
var href = window.URL.createObjectURL(blob);
downloadElement.href = href;
downloadElement.download = decodeURIComponent(filename.split("filename=")[1]);
document.body.appendChild(downloadElement);
downloadElement.click();
document.body.removeChild(downloadElement);
// URL.revokeObjectURL()方法会释放一个通过URL.createObjectURL()创建的对象URL. 当你要已经用过了这个对象URL,然后要让浏览器知道这个URL已经不再需要指向对应的文件的时候,就需要调用这个方法.
window.URL.revokeObjectURL(href);  

前端需要做如下几步:

  • 指定响应体类型 responseType:'blob'
  • 获取后端定义的文件名const filename = res.headers["content-disposition"];
  • 构建一个a标签
  • 创建指向blob的链接
  • 将文件名,链接设置到a标签上
  • 将a标签添加到document上
  • 调用a标签点击事件
  • document删除a节点
  • 释放href指向blob
目录
相关文章
|
1月前
|
JSON 前端开发 Java
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
文章介绍了Java后端如何使用Spring Boot框架响应不同格式的数据给前端,包括返回静态页面、数据、HTML代码片段、JSON对象、设置状态码和响应的Header。
133 1
震惊!图文并茂——Java后端如何响应不同格式的数据给前端(带源码)
|
24天前
|
监控 JavaScript 前端开发
前端的混合之路Meteor篇(六):发布订阅示例代码及如何将Meteor的响应数据映射到vue3的reactive系统
本文介绍了 Meteor 3.0 中的发布-订阅模型,详细讲解了如何在服务器端通过 `Meteor.publish` 发布数据,包括简单发布和自定义发布。客户端则通过 `Meteor.subscribe` 订阅数据,并使用 MiniMongo 实现实时数据同步。此外,还展示了如何在 Vue 3 中将 MiniMongo 的 `cursor` 转化为响应式数组,实现数据的自动更新。
|
1月前
|
前端开发 小程序 Java
java基础:map遍历使用;java使用 Patten 和Matches 进行正则匹配;后端传到前端展示图片三种情况,并保存到手机
这篇文章介绍了Java中Map的遍历方法、使用Pattern和matches进行正则表达式匹配,以及后端向前端传输图片并保存到手机的三种情况。
19 1
|
1月前
|
存储 前端开发 Java
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
本文介绍了使用Kaptcha插件在SpringBoot项目中实现验证码的生成和验证,包括后端生成验证码、前端展示以及通过session进行验证码校验的完整前后端代码和配置过程。
95 0
验证码案例 —— Kaptcha 插件介绍 后端生成验证码,前端展示并进行session验证(带完整前后端源码)
|
1月前
|
JSON 前端开发 数据格式
@RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)
文章详细讲解了在SpringMVC中如何使用`@RequestMapping`进行路由映射,并介绍了前后端参数传递的多种方式,包括传递单个参数、多个参数、对象、数组、集合以及JSON数据,并且涵盖了参数重命名和从URL中获取参数的方法。
73 0
@RequestMapping运用举例(有源码) 前后端如何传递参数?后端如何接收前端传过来的参数,传递单个参数,多个参数,对象,数组/集合(有源码)
|
1月前
|
前端开发 JavaScript Java
导出excel的两个方式:前端vue+XLSX 导出excel,vue+后端POI 导出excel,并进行分析、比较
这篇文章介绍了使用前端Vue框架结合XLSX库和后端结合Apache POI库导出Excel文件的两种方法,并对比分析了它们的优缺点。
235 0
|
1月前
|
前端开发 JavaScript 小程序
前端uni开发后端用PHP的圈子系统该 如何做源码?
圈子系统系统基于TP6+Uni-app框架开发;客户移动端采用uni-app开发,管理后台TH6开发。系统支持微信公众号端、微信小程序端、H5端、PC端多端账号同步,可快速打包生成APP
|
1月前
|
前端开发 Java 数据库
springBoot:template engine&自定义一个mvc&后端给前端传数据&增删改查 (三)
本文介绍了如何自定义一个 MVC 框架,包括后端向前端传递数据、前后端代理配置、实现增删改查功能以及分页查询。详细展示了代码示例,从配置文件到控制器、服务层和数据访问层的实现,帮助开发者快速理解和应用。
|
7天前
|
存储 SQL API
探索后端开发:构建高效API与数据库交互
【10月更文挑战第36天】在数字化时代,后端开发是连接用户界面和数据存储的桥梁。本文深入探讨如何设计高效的API以及如何实现API与数据库之间的无缝交互,确保数据的一致性和高性能。我们将从基础概念出发,逐步深入到实战技巧,为读者提供一个清晰的后端开发路线图。
|
6天前
|
JSON 前端开发 API
后端开发中的API设计与文档编写指南####
本文探讨了后端开发中API设计的重要性,并详细阐述了如何编写高效、可维护的API接口。通过实际案例分析,文章强调了清晰的API设计对于前后端分离项目的关键作用,以及良好的文档习惯如何促进团队协作和提升开发效率。 ####