下载文件,浏览器阻止不安全下载
背景:
在项目开发中,遇到需要下载文件的情况,文件类型可能是图片、excell表、pdf、zip等文件类型,但浏览器会阻止不安全的下载链接。
效果展示:

下载文件的两种方式:
一、根据接口的相对url,拼接成完整路径下载
这串完整的下载路径是:
开发预留

在浏览器访问,图片如下:
结果分析:
直接在浏览器就可以直接访问,可见这个文件没有加密,是不安全的。
还有一个原因是实际情况,根据接口的url直接下载的。另外一种导出下载,是发起网络请求的,接收后台传给前端的二进制流之前需要先设置responseType为blob,否则默认会以json获取,下载下来的文件打开会提示文件已损坏。是发起网络请求的,并且后端接口返回的response头的content-type也是对应的类型,我的这里是application/vnd.ms-excel;charset=UTF-8。
二、网络接口,导出excell表格
实现效果:


导出接口:

这个接口返回的数据在控制台打印:

备注:控制台输出的可以看到是个正确的Blob对象,这就说明我们的配置是对的。
实现思路【重点】:
导出接口传参给后端,后端对请求到的数据经过后端拼接,然后输出二进制流文件,然后给前端返回,前端直接下载。
需要注意几点:
1.前端请求需要携带请求体,config里面要带上responseType: 'blob'。举例:
//导出文件【渡船管理】
exportCrewInfoFile(params) {
return request.Get("/data/ferryShip/download?", params, {
headers: {
"Content-Type": "application/json",
},
responseType: 'blob',
});
},
所以我们接收后台传给前端的二进制流之前需要先设置responseType为blob,否则默认会以json获取,下载下来的文件打开会提示文件已损坏。
2.后端最好也要配置response头的content-type为对应的类型。
3.需要给这个Blob对象设置一个type,这个type表明改Blob对象所包含数据的MIME类型。如果类型未知,则该值为空字符串。例如:type: "application/vnd.ms-excel",
/**
*
* @param {*} res 接口返回的文件流
*/
export const dowloadFileUrl = (res) => {
console.log(res)
const fileNames = res.headers['content-disposition']
if (fileNames) {
//解码
const fileName = decodeURIComponent(fileNames.match(/=(.*)$/)[1])
// 处理返回的文件流
const content = res.data
const blob = new Blob([content], {
// type: res.data.type||"application/vnd.ms-excel",
type: res.data.type||"application/octet-stream; charset=utf-8"
});
if ('download' in document.createElement('a')) {
//非IE下载
const a = document.createElement('a') //创建一个a标签
a.download = fileName //指定文件名称
a.style.display = 'none' //页面隐藏
a.href = URL.createObjectURL(blob) // href用于下载地址
document.body.appendChild(a) //插到页面上
a.click() //通过点击触发
URL.revokeObjectURL(a.href) //释放URL 对象
document.body.removeChild(a) //删掉a标签
} else {
//IE10 + 下载
navigator.msSaveBlob(blob, fileName)
}
}
}
三、下载文件的两种方式的对比
实现代码:
代码1:
if (!data.file) {ElMessage.error("文件不存在!");return;}const url = BASEUrl + "/file/" + data.file;//拼接下载地址const a = document.createElement("a"); //创建一个a标签a.download = data.name; //指定文件名称a.style.display = "none"; //页面隐藏a.href = url; // href用于下载地址document.body.appendChild(a); //插到页面上a.click(); //通过点击触发URL.revokeObjectURL(a.href); //释放URL 对象document.body.removeChild(a); //删掉a标签
代码2:
/**** @param {*} fileContent 文件本体* @param {*} _fileName 自定义文件名*/
export const exportFileUtil = (fileContent, _fileName) => {const content = fileContent;const blob = new Blob([content], {type: fileContent.type || "application/octet-stream; charset=utf-8",});const fileName = _fileName;if ("download" in document.createElement("a")) {//非IE下载const a = document.createElement("a"); //创建一个a标签a.download = fileName; //指定文件名称a.style.display = "none"; //页面隐藏a.href = URL.createObjectURL(blob); // href用于下载地址document.body.appendChild(a); //插到页面上a.click(); //通过点击触发URL.revokeObjectURL(a.href); //释放URL 对象document.body.removeChild(a); //删掉a标签} else {//IE10 + 下载navigator.msSaveBlob(blob, fileName);}
};
/*** * @param {*} res 接口返回的文件流*/
export const dowloadFileUrl = (res) => {console.log(res)const fileNames = res.headers['content-disposition']if (fileNames) {//解码const fileName = decodeURIComponent(fileNames.match(/=(.*)$/)[1])// 处理返回的文件流const content = res.dataconst blob = new Blob([content], {// type: res.data.type||"application/vnd.ms-excel",type: res.data.type||"application/octet-stream; charset=utf-8"});if ('download' in document.createElement('a')) {//非IE下载const a = document.createElement('a') //创建一个a标签a.download = fileName //指定文件名称a.style.display = 'none' //页面隐藏a.href = URL.createObjectURL(blob) // href用于下载地址document.body.appendChild(a) //插到页面上a.click() //通过点击触发URL.revokeObjectURL(a.href) //释放URL 对象document.body.removeChild(a) //删掉a标签} else {//IE10 + 下载navigator.msSaveBlob(blob, fileName)}}
}
总结:
直接拼接url为下载路径,创建一个a标签触发下载;
导出接口通过接口返回的二进制流,经过出来二进制流为Blob且type类型与接口一致。
三、补充理论知识
MIME类型是什么:点击访问

MIME类型有哪些: 点击访问

常见MIME【媒体类型】 ,如下:
扩展名----------MIME类型
.csv--------------text/csv
.jpeg/.jpg-------image/jpeg
.png-------------image/png
.rar--------------application/x-rar-compressed
.doc-------------application/msword
.docx-----------application/vnd.openxmlformats-officedocument.wordprocessingml.document
.xls--------------application/vnd.ms-excel
.xlsx------------application/vnd.openxmlformats-officedocument.spreadsheetml.sheet
.zip--------------application/zip
相关文章:
下载文件,浏览器阻止不安全下载
背景: 在项目开发中,遇到需要下载文件的情况,文件类型可能是图片、excell表、pdf、zip等文件类型,但浏览器会阻止不安全的下载链接。 效果展示: 下载文件的两种方式: 一、根据接口的相对url,拼…...
基于javaweb的SpringBoot景区旅游管理系统设计和实现(源码+文档+部署讲解)
个人名片 🔥 源码获取 | 毕设定制| 商务合作:《个人名片》 ⛺️心若有所向往,何惧道阻且长 文章目录 个人名片运行环境技术栈适用功能说明使用说明 运行环境 Java≥8、MySQL≥5.7 1.运行环境:最好是java jdk 1.8,我们在这个平台…...
【17】Word:林楚楠-供应链❗
目录 题目 NO1.2 NO3 NO4 NO5 NO6 NO7 NO89 题目 NO1.2 另存为:文件→另存为→文档→文件名/考生文件夹F12/FnF12→文件名/考生文件夹 插入→分节符→文本框→输入文件→排版_居中对齐→间距/回车去掉文本框的边框→选中文本框→格式:形状轮廓…...
Transformer中基于惊喜的遗忘机制
在语言建模任务上,拥有 760M 参数的 Titans(MAC) 在 WikiText 上达到了 19.93 的困惑度,显著优于同等规模的 Transformer++(25.21) 和 Mamba2(22.94)。在常识推理任务上,Titans 在包括 PIQA、HellaSwag、WinoGrande 等 9 个基准测试中的平均准确率达到 52.51%,超过了现…...
从玩具到工业控制--51单片机的跨界传奇【3】
在科技的浩瀚宇宙中,51 单片机就像一颗独特的星辰,散发着神秘而迷人的光芒。对于无数电子爱好者而言,点亮 51 单片机上的第一颗 LED 灯,不仅仅是一次简单的操作,更像是开启了一扇通往新世界的大门。这小小的 LED 灯&am…...
基于机器学习的用户健康风险分类及预测分析
完整源码项目包获取→点击文章末尾名片! 背景描述 在这个日益注重健康与体能的时代,健身已成为许多人追求健康生活的重要组成部分。 本数据集包含若干健身房会员的详细信息,包括年龄、性别、体重、身高、心率、锻炼类型、身体脂肪比例等多项关…...
CF 641A.Little Artem and Grasshopper(Java实现)
题目分析 蚂蚱会在n个房间中根据既定房间规则向固定方向跳跃固定长度,试问是否能够跳出这个长度(即落点位置在0或n1) 思路分析 输入n就有n个房间,n套规则(固定方向和跳跃距离),蚂蚱到哪个房间就…...
5 分钟复刻你的声音,一键实现 GPT-Sovits 模型部署
想象一下,只需简单几步操作,就能生成逼真的语音效果,无论是为客户服务还是为游戏角色配音,都能轻松实现。GPT-Sovits 模型,其高效的语音生成能力为实现自然、流畅的语音交互提供了强有力的技术支持。本文将详细介绍如何…...
1.Spring AI 从入门到实践
Spring AI 从入门到实践 1.什么是Spring AI 2.使用Spring Boot&Spring AI快速构建AI应用程序 3.ChatClient&Chat Model简化与AI模型的交互 4.Spring AI Prompt:与大模型进行有效沟通 5.结构化输出大模型响应 6.实战:AI聊天机器人 Ben技术站关注Java技术&#x…...
第23篇 基于ARM A9处理器用汇编语言实现中断<五>
Q:怎样修改HPS Timer 0定时器产生的中断周期? A:在上一期实验的基础上,可以修改按键中断服务程序,实现红色LED上的计数值递增的速率,主程序和其余代码文件不用修改。 实现以下功能:按下KEY0…...
攻防世界 unseping
开启场景 整体来说是创建了一个case类,然后可接受post传来的ctf的值,并对其进行base64解码以及反序列化。所以我们能控制ctf变量。 先看__wakeup方法,该方法使用waf方法对$arg中的内容进行了防护,过滤掉了| & ; 空格 / cat f…...
Python编程与在线医疗平台数据挖掘与数据应用交互性研究
一、引言 1.1 研究背景与意义 在互联网技术飞速发展的当下,在线医疗平台如雨后春笋般涌现,为人们的就医方式带来了重大变革。这些平台打破了传统医疗服务在时间和空间上的限制,使患者能够更加便捷地获取医疗资源。据相关报告显示,中国基于互联网的医疗保健行业已进入新的…...
浔川 AI 翻译已修复,可正常使用
浔川 AI 翻译已修复,可正常使用 亲爱的用户们: 大家好!经过技术团队的不懈努力,浔川 AI 翻译平台已完成修复,目前各项功能均已恢复正常,可流畅使用。在此,我们向一直以来关心和支持浔川 AI 翻译…...
apidoc thinkphp likeadmin 遇到解析报错
报错: [Semantical Error] The annotation "notes" in method app\adminapi\controller\article\ArticleCateController::lists() was never imported. Did you maybe forget to add a "use" statement for this annotation? 解决办法: config/apidoc…...
第22篇 基于ARM A9处理器用汇编语言实现中断<四>
Q:怎样编写ARM A9处理器汇编语言代码配置使用按键和定时器中断? A:本次实验同样为中断模式和监督模式都设置ARM A9堆栈指针,并使能中断,此外在主程序中调用子程序CONFIG_HPS_TIMER和CONFIG_KEYS分别对HPS Timer 0&…...
重回C语言之老兵重装上阵(六)枚举
1. 什么是枚举 (enum)? 枚举(enum)是 C 语言中的一种数据类型,用于定义一组具名的整数常量。它可以使代码更加可读,帮助程序员更容易理解程序中的常量值。通过枚举,程序员可以使用有意义的名称来代替数字&…...
STL-list类
list的介绍和使用 list的介绍 list的介绍list的介绍 list是双向循环链表 list的使用 构造 list(size_t n,const value_type& val value_type())构造的list中包含n个值为val的元素list()构造空listlis(const list& x)拷贝构造函数list(inputlerator first,inputlter…...
Hanlp的学习
参考:HanLP 自然语言处理使用总结-CSDN博客 参考:Sprint Boot 工程中HanLP配置相对路径,始终有问题的解决方案_springboot hanlp-CSDN博客 <!--hanlp 依赖--><dependency><groupId>com.hankcs</groupId><artifa…...
Excel中函数SIGN()的用法
Excel中函数SIGN的用法 1. 函数详细讲解1.1 函数解释1.2 使用格式1.3 参数定义1.4 要点 2. 实用演示示例2.1 函数需求2.2 公式编写 3. 注意事项4. 文档下载5. 其他文章6. 获取全部Excel练习素材快来试试吧🥰 函数练习素材👈点击即可进行下载操作操作注意…...
如何将本地电脑上的文件夹设置为和服务器的共享文件夹
将本地电脑上的文件夹设为与服务器共享的文件夹,通常是在本地开启文件共享,并配置相应的权限,使服务器可以访问该文件夹。以下以 Windows 系统为例说明具体操作步骤: 一、在本地电脑上设置共享文件夹 选择文件夹 找到需要共享的文…...
ESP32 I2S音频总线学习笔记(四): INMP441采集音频并实时播放
简介 前面两期文章我们介绍了I2S的读取和写入,一个是通过INMP441麦克风模块采集音频,一个是通过PCM5102A模块播放音频,那如果我们将两者结合起来,将麦克风采集到的音频通过PCM5102A播放,是不是就可以做一个扩音器了呢…...
PL0语法,分析器实现!
简介 PL/0 是一种简单的编程语言,通常用于教学编译原理。它的语法结构清晰,功能包括常量定义、变量声明、过程(子程序)定义以及基本的控制结构(如条件语句和循环语句)。 PL/0 语法规范 PL/0 是一种教学用的小型编程语言,由 Niklaus Wirth 设计,用于展示编译原理的核…...
云原生安全实战:API网关Kong的鉴权与限流详解
🔥「炎码工坊」技术弹药已装填! 点击关注 → 解锁工业级干货【工具实测|项目避坑|源码燃烧指南】 一、基础概念 1. API网关(API Gateway) API网关是微服务架构中的核心组件,负责统一管理所有API的流量入口。它像一座…...
DAY 26 函数专题1
函数定义与参数知识点回顾:1. 函数的定义2. 变量作用域:局部变量和全局变量3. 函数的参数类型:位置参数、默认参数、不定参数4. 传递参数的手段:关键词参数5 题目1:计算圆的面积 任务: 编写一…...
sshd代码修改banner
sshd服务连接之后会收到字符串: SSH-2.0-OpenSSH_9.5 容易被hacker识别此服务为sshd服务。 是否可以通过修改此banner达到让人无法识别此服务的目的呢? 不能。因为这是写的SSH的协议中的。 也就是协议规定了banner必须这么写。 SSH- 开头,…...
链式法则中 复合函数的推导路径 多变量“信息传递路径”
非常好,我们将之前关于偏导数链式法则中不能“约掉”偏导符号的问题,统一使用 二重复合函数: z f ( u ( x , y ) , v ( x , y ) ) \boxed{z f(u(x,y),\ v(x,y))} zf(u(x,y), v(x,y)) 来全面说明。我们会展示其全微分形式(偏导…...
rm视觉学习1-自瞄部分
首先先感谢中南大学的开源,提供了很全面的思路,减少了很多基础性的开发研究 我看的阅读的是中南大学FYT战队开源视觉代码 链接:https://github.com/CSU-FYT-Vision/FYT2024_vision.git 1.框架: 代码框架结构:readme有…...
小智AI+MCP
什么是小智AI和MCP 如果还不清楚的先看往期文章 手搓小智AI聊天机器人 MCP 深度解析:AI 的USB接口 如何使用小智MCP 1.刷支持mcp的小智固件 2.下载官方MCP的示例代码 Github:https://github.com/78/mcp-calculator 安这个步骤执行 其中MCP_ENDPOI…...
工厂方法模式和抽象工厂方法模式的battle
1.案例直接上手 在这个案例里面,我们会实现这个普通的工厂方法,并且对比这个普通工厂方法和我们直接创建对象的差别在哪里,为什么需要一个工厂: 下面的这个是我们的这个案例里面涉及到的接口和对应的实现类: 两个发…...
标注工具核心架构分析——主窗口的图像显示
🏗️ 标注工具核心架构分析 📋 系统概述 主要有两个核心类,采用经典的 Scene-View 架构模式: 🎯 核心类结构 1. AnnotationScene (QGraphicsScene子类) 主要负责标注场景的管理和交互 🔧 关键函数&…...

