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

简介: 今天给大家带来一个小知识,那就是分别从前端和后端同学的不同角度看他们是如何处理文件下载的,这个知识不光能有助于我们处理文件导出的需求,也能加深我们对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
目录
相关文章
|
17天前
|
前端开发 JavaScript 关系型数据库
从前端到后端:构建现代化Web应用的技术探索
在当今互联网时代,Web应用的开发已成为了各行各业不可或缺的一部分。从前端到后端,这篇文章将带你深入探索如何构建现代化的Web应用。我们将介绍多种技术,包括前端开发、后端开发以及各种编程语言(如Java、Python、C、PHP、Go)和数据库,帮助你了解如何利用这些技术构建出高效、安全和可扩展的Web应用。
|
18天前
|
前端开发 小程序 Java
uniapp上传图片 前端以及java后端代码实现
uniapp上传图片 前端以及java后端代码实现
32 0
|
14天前
|
小程序 前端开发 JavaScript
小程序全栈开发:前端与后端的完美结合
【4月更文挑战第12天】本文介绍了小程序全栈开发,涵盖前端和后端的关键点。前端使用WXML和WXSS进行页面结构和样式设计,JavaScript处理逻辑及组件使用;后端采用Node.js等语言处理业务逻辑、数据库设计和API接口开发。前端与后端通过数据交互实现结合,采用前后端分离模式,支持跨平台运行。调试测试后,提交微信审核并上线运营。掌握前端后端结合是小程序成功的关键。
|
14天前
|
Web App开发 移动开发 运维
跨域解决方案[前端+后端]
跨域解决方案[前端+后端]
25 0
|
15天前
|
JavaScript 前端开发 API
游戏开发入门:Python后端与Vue前端的协同工作方式
【4月更文挑战第11天】使用Python后端(Flask或Django)和Vue.js前端开发游戏变得流行,能提高开发效率和可维护性。本文指导如何构建这样的项目,包括设置环境、创建虚拟环境、搭建后端API及前端Vue组件,强调前后端协作和API接口的重要性。这种架构促进团队合作,提升代码质量和游戏体验。
|
16天前
|
供应链 JavaScript 前端开发
使用Django和Vue实现电子商务网站的后端和前端
【4月更文挑战第10天】本文介绍了使用Django和Vue构建电子商务网站的后端与前端方法。Django作为Python的Web框架负责后端,其模型-视图-控制器设计简化了商品管理、购物车和订单处理。Vue.js用于前端,提供数据驱动和组件化的用户界面。通过定义Django模型和视图处理请求,结合Vue组件展示商品和管理购物车,开发者可构建交互性强的电商网站。虽然实际开发涉及更多细节,但本文为入门提供了基础指导。
|
29天前
|
前端开发 JavaScript NoSQL
从前端到后端:构建全栈应用的技术挑战与解决方案
在当今互联网时代,全栈开发成为越来越受欢迎的技术趋势。本文将深入探讨从前端到后端的全栈开发过程中所面临的技术挑战,并提出相应的解决方案,涵盖前端框架选择、后端技术架构、数据库设计以及跨平台兼容性等关键问题。
|
8月前
|
Web App开发 前端开发 JavaScript
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-fiber解决了什么问题
95 0
|
8月前
|
前端开发 定位技术
前端学习笔记202305学习笔记第二十三天-地图单线程配置
前端学习笔记202305学习笔记第二十三天-地图单线程配置
64 0
前端学习笔记202305学习笔记第二十三天-地图单线程配置
|
8月前
|
前端开发 API
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
前端学习笔记202307学习笔记第五十七天-模拟面试笔记react-react-redux的工作流程
55 0