前端文件下载的方式

方式一:a标签直接下载

<a href="链接" >下载</a>

一个文件链接(一般是服务器上的某个文件),这个链接一般地址栏输入是预览,不是附件下载

如果想改成附件下载,以下两种方式任选一个均可:
1、后端处理,后端加上一个响应头

res.setHeader('Content-Dispostion', 'attachment', 'name.pdf')

2、a标签 加上 download属性

<a href="链接" download="文件名" >下载</a>

方式一的缺点:

缺点:在 JavaScript 中使用 a 标签下载文件时,直接通过 a标签的点击事件触发下载,是无法设置请求头的,因为这是一个简单的 GET 请求。如果这个文件的下载要求的是携带token,那a标签这种就不生效了(a标签没法携带token),会成为预览。
方案:a标签可以携带cookie,所以可以有另一种解决方法,在下载文件前,发送一个请求获取一个临时token通过cookie进行携带,a标签下载是流式下载,会把服务器的文件像流水一样存储到本地磁盘,所以下载直接能看到下载,不会将文件缓存到浏览器。

标题方式二:使用 XMLHttpRequest 或 Fetch API 请求。

写一个方法进行下载 (本质还是利用a标签进行下载)
这个方法可以是一个ajax请求,这个请求就可以携带token,然后将请求到的服务器文件转成blob,在创建一个a标签进行下载,创建虚拟的链接元素,模拟点击下载。


import fetch from 'isomorphic-fetch';
const exportFile = (url, options) => {const projectId = sessionStorage.getItem(PROJECT_ID);const downLoadURL = projectId ? BATCH_ACTION_URL_PREFIX.V2 : BATCH_ACTION_URL_PREFIX.V1;const defaultOptions = {credentials: 'same-origin',};const newOptions = { ...defaultOptions, ...options };if (newOptions.method === 'POST' ||newOptions.method === 'PUT' ||newOptions.method === 'DELETE') {const projectId = sessionStorage.getItem(PROJECT_ID);const appId = sessionStorage.getItem(APP_ID);const shopId = sessionStorage.getItem(SHOP_ID);const params = {};projectId && Object.assign(params, { projectId });appId && Object.assign(params, { appId });shopId && Object.assign(params, { shopId });newOptions.body = { ...newOptions.body, ...params };if (!(newOptions.body instanceof FormData)) {newOptions.headers = {Accept: 'application/json','Content-Type': 'application/json; charset=utf-8',...newOptions.headers,};} else {// newOptions.body is FormDatanewOptions.headers = {Accept: 'application/json',...newOptions.headers,};}}const token = window.localStorage.getItem(TOKEN);if (token) {newOptions.headers = {'X-Authorization': `Bearer ${token}`,...newOptions.headers,};}const lang = localStorage.getItem(LOCALE_KEY);if (lang) {newOptions.headers = {'Accept-Language': lang,...newOptions.headers,};}const requestURL = `${downLoadURL}/${url}`;return request(requestURL, newOptions).then(res => {let filename;if (res.headers) {filename = (res.headers.get('Content-Disposition') || res.headers.get('content-disposition')).split('attachment;filename=')[1];}if (res.blob) {res.blob().then(blob => {var alink = document.createElement('a');alink.style.display = 'none';alink.target = '_blank';if (window.navigator && window.navigator.msSaveOrOpenBlob) {// 兼容IE/Edgewindow.navigator.msSaveOrOpenBlob(blob, filename);} else {alink.href = window.URL.createObjectURL(blob);alink.download = filename;}document.body.appendChild(alink);alink.click();URL.revokeObjectURL(alink.href); // 释放URL 对象document.body.removeChild(alink);});return res;} else {if (res.code === 0) {return res;} else {message.warning(res.message);}}});
};export default exportFile;export default function request(url: string, options: Object) {const defaultOptions = {credentials: 'same-origin',};const newOptions = { ...defaultOptions, ...options };if (newOptions.method === 'POST' ||newOptions.method === 'PUT' ||newOptions.method === 'DELETE' ||newOptions.method === 'PATCH') {if (!(newOptions.body instanceof FormData)) {newOptions.headers = {Accept: 'application/json','Content-Type': 'application/json; charset=utf-8',...newOptions.headers,};newOptions.body = JSON.stringify(newOptions.body);} else {// newOptions.body is FormDatanewOptions.headers = {Accept: 'application/json',...newOptions.headers,};}}return fetch(url, newOptions).then(response => checkStatus(response, url, options));
}

方式二的缺点:

**如果文件小还行,文件大了就会出现点击了下载,但是没有反应,过了几分钟后才出现了下载,这种等待时间就是将服务器端的那个文件转成了blob(res.blob()花的时间特别长),才进行a标签的流式下载(这里页面才开始出现有下载的交互体现)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/45170.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【鸿蒙学习笔记】关系型数据库概述

目录标题 关系型数据库的运行机制样例代码共通方法 DBUtilsIndex 代码效果 关系型数据库的运行机制 1、 关系型数据库对应用提供通用的操作接口&#xff0c;底层使用SQLite作为持久化存储引擎&#xff0c;支持SQLite具有的数据库特性&#xff0c;包括但不限于事务、索引、视图…

自建邮件服务器有哪些方法步骤与注意事项?

自建邮件服务器如何设置解析&#xff1f;邮件服务器怎么使用&#xff1f; 自建邮件服务器可以为个人或企业提供更多的灵活性和控制权&#xff0c;然而&#xff0c;这也是一个复杂且需要谨慎处理的任务。AokSend将探讨自建邮件服务器的基本方法步骤和需要注意的事项。 自建邮件…

数据库(mysql)忘记密码解决办法

步骤一&#xff1a;先停止数据库服务 [rootGGB ~]# systemctl stop mysql.service [rootGGB ~]# systemctl status mysql.service ● mysql.service - MySQL ServerLoaded: loaded (/etc/systemd/system/mysql.service; enabled; vendor preset: disabled)Active: fail…

逻辑回归(纯理论)

1.什么是逻辑回归&#xff1f; 逻辑回归是一种常用的统计学习方法&#xff0c;主要用于解决分类问题。尽管名字中包含"回归"&#xff0c;但它实际上是一种分类算法 2.为什么机器学习需要使用逻辑回归 1.二元分类 这是逻辑回归最基本和常见的用途。它可以预测某个事…

鸿蒙开发:Universal Keystore Kit(密钥管理服务)【HMAC(C/C++)】

HMAC(C/C) HMAC是密钥相关的哈希运算消息认证码&#xff08;Hash-based Message Authentication Code&#xff09;&#xff0c;是一种基于Hash函数和密钥进行消息认证的方法。 在CMake脚本中链接相关动态库 target_link_libraries(entry PUBLIC libhuks_ndk.z.so)开发步骤 生…

计算机SCI期刊,闭眼投,保证检索,命中率100%

一、期刊名称 Pervasive and Mobile Computing 二、期刊简介 期刊类型&#xff1a;SCI 学科领域&#xff1a;计算机 影响因子&#xff1a;3 中科院分区&#xff1a;3区 三、期刊简介 Pervasive and Mobile Computing Journal &#xff08;PMC&#xff09; 是一本高影响力…

基于前馈神经网络 FNN 实现股票单变量时间序列预测(PyTorch版)

前言 系列专栏:【深度学习:算法项目实战】✨︎ 涉及医疗健康、财经金融、商业零售、食品饮料、运动健身、交通运输、环境科学、社交媒体以及文本和图像处理等诸多领域,讨论了各种复杂的深度神经网络思想,如卷积神经网络、循环神经网络、生成对抗网络、门控循环单元、长短期记…

自定义View-渐变TextView(重点:绘制文本)

源码链接 夸克网盘分享 效果展示 分析 动态效果&#xff0c;使用Animator实现自定义View 继承TextView使用TextView的测量&#xff0c;不重写使用TextView的布局&#xff0c;不重写绘制-重写绘制 使用两种颜色绘制文本颜色占比不同&#xff0c;百分比从0~1 实现 自定义属性…

Vue使用socket实现实时通信

一、新建socket文件 class SocketService {constructor() {this.socket null;this.reconnectTimer null;this.messageCallback null;this.connectionParams null;this.pathnull}init() {this.clearReconnectTimer(); // 尝试重新连接之前先清除重连定时器if (typeof WebSo…

论文发表作图必备:训练结果对比,多结果绘在一个图片【Precision】【Recall】【mAP0.5】【mAP0.5-0.95】【loss】

前言:Hello大家好,我是小哥谈。YOLO(You Only Look Once)算法是一种目标检测算法,它可以在图像中实时地检测和定位目标物体。YOLO算法通过将图像划分为多个网格,并在每个网格中检测目标物体,从而实现快速的目标检测。本文所介绍的作图教程适用于所有YOLO系列版本算法,接…

Go泛型详解

引子 如果我们要写一个函数分别比较2个整数和浮点数的大小&#xff0c;我们就要写2个函数。如下&#xff1a; func Min(x, y float64) float64 {if x < y {return x}return y }func MinInt(x, y int) int {if x < y {return x}return y }2个函数&#xff0c;除了数据类…

Idea在线搜索Maven依赖-好用工具分享

maven_search 等价于网页搜索maven依赖&#xff0c;非常方便快捷 下载安装后&#xff0c;使用&#xff1a; 点击上方Tools Maven Search 或者快捷键 Ctrl Shift M 最后选择依赖&#xff0c;复制即可

Vue 3 与 TypeScript:最佳实践详解

大家好,我是CodeQi! 很多人问我为什么要用TypeScript? 因为 Vue3 喜欢它! 开个玩笑... 在我们开始探索 Vue 3 和 TypeScript 最佳实践之前,让我们先打个比方。 如果你曾经尝试过在没有 GPS 的情况下开车到一个陌生的地方,你可能会知道那种迷失方向的感觉。 而 Typ…

昇思学习打卡-17-热门LLM及其他AI应用/基于MobileNetv2的垃圾分类

文章目录 网络介绍读取数据集训练训练策略模型保存损失函数优化器模型训练 网络介绍 MobileNetv2专注于移动端、嵌入式或IoT设备的轻量级CNN网络。MobileNet网络使用深度可分离卷积&#xff08;Depthwise Separable Convolution&#xff09;的思想在准确率小幅度降低的前提下&…

分享一款嵌入式开源LED指示灯控制代码框架cotLed

一、工程简介 cotLed是一款轻量级的LED控制软件框架&#xff0c;可以十分方便地控制及自定义LED的各种状态&#xff0c;移植方便&#xff0c;无需修改&#xff0c;只需要在初始化时实现单片机硬件GPIO初始化&#xff0c;同时为框架接口提供GPIO写函数即可。 框架代码工程地址&a…

Apache Dubbo与Nacos整合过程

Dubbo服务发现 Dubbo 提供的是一种 Client-Based 的服务发现机制&#xff0c;依赖第三方注册中心组件来协调服务发现过程&#xff0c;支持常用的注册中心如 Nacos、Consul、Zookeeper 等。 以下是 Dubbo 服务发现机制的基本工作原理图&#xff1a; 服务发现包含提供者、消费者…

【深度学习】图形模型基础(7):机器学习优化中的方差减少方法(2)

4.高级算法 本节将探讨基本变分减少&#xff08;VR&#xff09;方法的几种拓展。这些拓展旨在处理更广泛的应用场景&#xff0c;包括非光滑问题和/或非强凸问题。此外&#xff0c;一些拓展利用算法技巧或问题结构的特性&#xff0c;设计出比基础方法更高效的算法。 4.1. SGD与…

LabVIEW中使用 DAQmx Connect Terminals作用意义

该图展示了如何在LabVIEW中使用 DAQmx Connect Terminals.vi 将一个信号从一个源端口连接到一个目标端口。这种处理有以下几个主要目的和作用&#xff1a; 同步操作&#xff1a; 在多任务、多通道或多设备系统中&#xff0c;可能需要不同的组件在同一时刻执行某些操作。通过将触…

Windows下终端Kafka指令常用操作

1、创建Topic kafka-topics.bat --create --bootstrap-server localhost:9092 --replication-factor 1 --partitions 1 --topic test 2、查看Topic列表 kafka-topics.bat --list --bootstrap-server localhost:9092 3、设置Topic最大消息大小 kafka-topics.bat --bootstrap-s…

在Spring Boot中集成单元测试框架

在Spring Boot中集成单元测试框架 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. 单元测试概述 在软件开发中&#xff0c;单元测试是保证代码质量和功能正确性的重要手段。Spring Boot框架支持…