后端返回一个图片链接,前端如何实现下载功能?

纯原创文章,转载请说明来源。

一、背景

要实现一个下载功能,后端直接返回了一个图片的地址https://xxxxx/pic.jpg。如果我们直接通过window.open(url, '_blank') 的方式去下载这个图片,会发现 Chrome 浏览器会对这个图片进行预览,而不是期望的下载。那要怎么做,才能实现这个下载呢?

二、代码实现

Step1. 封装下载通用的方法:

/*** 判断是否IE浏览器,为IE返回true* @returns {boolean}*/
export const isIE = (): boolean => {const userAgent = navigator.userAgent // 取得浏览器的userAgent字符串const isIE = userAgent.indexOf('compatible') > -1 && userAgent.indexOf('MSIE') > -1 // 判断是否IE<11浏览器const isEdge = userAgent.indexOf('Edge') > -1 && !isIE // 判断是否IE的Edge浏览器const isIE11 = userAgent.indexOf('Trident') > -1 && userAgent.indexOf('rv:11.0') > -1return isIE || isEdge || isIE11
}/*** 尝试从Blob中保存文件作为JSON* 先尝试将Blob转换为文本并解析为JSON,如果失败(即不是有效的JSON),则调用另一个函数来处理文件的保存* @param fileName 文件名* @param blob* @param fileMime MIME 类型*/
export const attemptSaveFileFromBlobAsJson = (fileName: string, blob: Blob, fileMime: string) => {const fileReader: any = new FileReader()fileReader.readAsText(blob)fileReader.onloadend = () => {try {// 转换解析结果,转换成功代表后端抛错 { code: 400, msg: 'xxx' }JSON.parse(fileReader.data)} catch (err) {saveFileFromBlobDirectly(fileName, blob, fileMime)}}
}/*** 直接保存Blob为文件* @param fileName 文件名* @param blob* @param fileMime MIME 类型*/function saveFileFromBlobDirectly(fileName: string, blob: Blob, fileMime: string) {try {// 下载文件const fileBlob = new Blob([blob], {type: fileMime})if (!isIE()) {// 非IE下载const elink = document.createElement('a')elink.download = fileNameelink.style.display = 'none'elink.target = '_blank'elink.href = URL.createObjectURL(fileBlob)document.body.appendChild(elink)elink.click()URL.revokeObjectURL(elink.href) // 释放URL 对象document.body.removeChild(elink)} else {// IE10+下载;(navigator as any).msSaveBlob(fileBlob, fileName)}} catch (err) {console.error(err)}
}/*** 通过url获取文件名* @param url* @returns*/
export function getFileNameFromUrl(url: string): string | null {try {const parsedUrl = new URL(url)const path = parsedUrl.pathnameconst lastIndex = path.lastIndexOf('/')return lastIndex === -1 ? null : path.substring(lastIndex + 1)} catch (error) {// 如果URL格式不正确,捕获错误并返回null或抛出错误console.error('Invalid URL:', error)return null}
}

Setp2. 封装发送图片请求的方法

import http from '@/plugins/axios'
/*** 获取图片*/
export const gePicBlob = (url: string) => {return http.get<never, any>(url, { responseType: 'blob' })
}
// axios实例需要做一点点改造
const instance = axios.create({// ... 省略相关配置
})
/*** 返回后置拦截*/
instance.interceptors.response.use(function (response) {// blob 类型 直接返回if (response?.config?.responseType === 'blob') return response.data// 省略其余的业务逻辑}
)

Step3. 使用刚刚封装的方法

/*** 点击下载按钮时触发*/
async function downloadOnClick(downloadUrl?: string) {if (!downloadUrl) {return}try {const fileName = getFileNameFromUrl(downloadUrl) || '下载.jpg'const data = await gePicBlob(downloadUrl)attemptSaveFileFromBlobAsJson(fileName, data, data.type)} catch (ex) {console.error(ex)}
}

三、实现逻辑

  1. 获取图片 Blob
    gePicBlob 函数通过 GET 请求从指定的 URL(后端返回的图片链接)获取图片数据并设置响应类型为 blob。这意味着返回的响应体将直接作为 Blob 对象处理。
    注意事项:发送请求时,如果因为图片资源的域名和当前域名不一致导致跨域,那么我们需要在 nginx 进行配置,通过Access-Control-Allow-Origin配置允许当前的域名访问图片资源。

  2. 处理 Blob 对象
    downloadOnClick 函数中,首先通过 gePicBlob 获取图片的 Blob 对象及其 MIME 类型(通过 data.type 获取)。
    然后,调用 attemptSaveFileFromBlobAsJson 函数,一旦遇到解析错误(即 Blob 不是有效的 JSON),就会直接调用 saveFileFromBlobDirectly 来下载文件。

  3. 直接下载文件
    saveFileFromBlobDirectly 函数是实际执行下载操作的函数。它首先创建一个新的 Blob 对象(为了确保 MIME 类型被正确设置)。
    接着,根据浏览器类型(是否为 IE),使用不同的方法来触发下载。对于非 IE 浏览器,它创建一个临时的 <a> 标签,设置其 href 为 Blob 对象的 URL(通过 URL.createObjectURL 生成),并模拟点击该链接来触发下载。对于 IE 浏览器,则使用 navigator.msSaveBlob 方法。

四、结果

实现下载啦~
在这里插入图片描述

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

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

相关文章

魅族手机怎么录屏?详细步骤助你轻松上手

“有人知道魅族手机怎么录屏吗&#xff0c;最近我在准备一些教学视频&#xff0c;急需用到手机的录屏功能来记录操作过程&#xff0c;但遗憾的是&#xff0c;我翻遍了设置也没能找到录屏的开关。所以&#xff0c;我在这里想问问大家&#xff0c;魅族手机是如何启动录屏功能的&a…

【PyTorch】图像多分类项目部署

【PyTorch】图像多分类项目 【PyTorch】图像多分类项目部署 如果需要在独立于训练脚本的新脚本中部署模型&#xff0c;这种情况模型和权重在内存中不存在&#xff0c;因此需要构造一个模型类的对象&#xff0c;然后将存储的权重加载到模型中。 加载模型参数&#xff0c;验证模型…

图解 HDFS 架构 |读写过程

HDFS HDFS 全称 Hadoop Distributed File System&#xff0c;是一个分布式文件系统。HDFS&#xff08;Hadoop Distributed File System&#xff09;是 Apache Hadoop 生态系统的一部分&#xff0c;它是一个分布式文件系统&#xff0c;用于存储和处理大规模数据集。HDFS 专门设…

源代码防泄密如何做?企业如何有效选择源代码防泄密产品?

源代码防泄密怎么选&#xff1f;如何高效做源代码防泄密工作&#xff1f; 源代码开发环境复杂&#xff0c;涉及的开发软件和文件类型众多且变化多端&#xff0c;那么究竟有哪些源代码防泄密软件能够适应各种开发软件而不影响原有的工作效率呢&#xff1f; 对于研发人员来说&a…

探索 Framer Motion 高级动画技巧:提升前端设计水平

在现代的网页和应用设计中&#xff0c;动画不仅仅是视觉的点缀&#xff0c;更是用户体验的重要组成部分。它能够使界面更具吸引力&#xff0c;提升交互的流畅性&#xff0c;甚至在不经意间传达品牌的个性和态度。然而&#xff0c;要创造出令人惊叹的动效并不容易——直到有了 F…

经验——OLED的使用

型号&#xff1a;HS96L01W 4S03 分辨率&#xff1a;120*64 通讯方式&#xff1a;4线SPI 模式00 MCU&#xff1a;MSPM0G3507&#xff08;只影响SPI的配置&#xff09; 原本照着型号搜到了嘉立创的使用文档&#xff0c;但是实际上并不能正常使用&#xff0c;后来寻到了一篇博客…

MFC与QT中禁用Esc、Alt+F4、关闭图标

在业务中&#xff0c;我们需要按指定的方式才能关闭当前对话框。如下图需输入密码点击确认后&#xff0c;界面才能关闭。 方法1&#xff1a;通过禁用界面的按钮以及键盘上对应关闭对话框的按键。 1.灰度化关闭按钮 在对话框初始化部分添加将关闭按钮禁用 //MFC CMenu *pSysMe…

主要的国产信创数据库有哪些

数据库生态分类 当前数据库生态可以大致分类三类: 一、传统商业数据库&#xff0c;以 Oracle 为代表&#xff0c;其在 40 余年时间里所创造的数据库帝国已拥有了极其完善的生态; 二、开源数据库&#xff0c;以 MYSQL、PostgreSQL为代表&#xff0c;遍布全球的社区组织形成了强…

大文件分片上传(前端TS实现)

大文件分片上传 内容 一般情况下&#xff0c;前端上传文件就是new FormData,然后把文件 append 进去&#xff0c;然后post发送给后端就完事了&#xff0c;但是文件越大&#xff0c;上传的文件也就越长&#xff0c;如果在上传过程中&#xff0c;突然网络故障&#xff0c;又或者…

AHK是让任何软件都支持 Shift + 鼠标滚轮 实现界面水平滚动

目录 基本介绍 详细特点 图解安装 下载失败&#xff1f;缓慢&#xff1f; 创建并运行脚本代码&#x1f603; 新建空 xxx.ahk文件 vscode/记事本等编辑工具打开 复制并粘贴简易脚本 运行 其他问题 问题一&#xff1a;弹出无法执行此脚本 关闭脚本 基本介绍 AutoHot…

【MetaGPT系列】【MetaGPT完全实践宝典——如何定义单一行为多行为Agent】

目录 前言一、智能体1-1、Agent概述1-2、Agent与ChatGPT的区别 二、多智能体框架MetaGPT2-1、安装&配置2-2、使用已有的Agent&#xff08;ProductManager&#xff09;2-3、拥有单一行为的Agent&#xff08;SimpleCoder&#xff09;2-3-1、定义写代码行为2-3-2、角色定义2-3…

B站音视频分开 大小问题

音频是33331 kb&#xff0c;视频是374661 kb 合并之后却是2561363 kb 这可能是B站音频和视频分开的原因吧

Zabbix监控案例

文章目录 一、监控linux TCP连接状态TCP端口的十一种连接状态自定义监控项监控示例二、监控模板监控tcp连接监控nginx 一、监控linux TCP连接状态 TCP&#xff0c;全称Transfer Control Protocol&#xff0c;中文名为传输控制协议&#xff0c;它工作在OSI的传输层&#xff0c;…

3.Fabric系统架构、网络拓扑图、交易流程

Hyperledger Fabric系统架构 Fabric网络拓扑图 Fabric交易流程 多通道

【数字范围按位与】python刷题记录

run到位运算。 顿悟&#xff1a; 只看第一个二进制位&#xff0c;只存在0,1两种情况&#xff0c;所以如果left<right&#xff0c;区间中必然存在left1,那么最低位&一下一定等于0了&#xff0c;然后不停的右移&#xff0c;一直移到两个相等为止&#xff0c;就这么简单 …

Qt自定义下拉列表-可为选项设置标题、可禁用选项

在Qt中,ComboBox&#xff08;组合框&#xff09;是一种常用的用户界面控件,它提供了一个下拉列表,允许用户从预定义的选项中选择一个。在项目开发中&#xff0c;如果简单的QComboBox无法满足需求&#xff0c;可以通过自定义QComboBox来实现更复杂的功能。本文介绍一个自定义的下…

二级医院LIS系统源码,医学检验系统,支持DB2,Oracle,MS SQLServer等主流数据库

系统概述&#xff1a; LIS系统即实验室信息管理系统。LIS系统能实现临床检验信息化&#xff0c;检验科信息管理自动化。其主要功能是将检验科的实验仪器传出的检验数据经数据分析后&#xff0c;自动生成打印报告&#xff0c;通过网络存储在数据库中&#xff0c;使医生能够通过医…

7.消息应答

消费者完成一个任务可能需要一段时间&#xff0c;如果其中一个消费者处理一个长时间的任务并且只完成了部分突然就挂掉了&#xff0c;会发生什么情况&#xff1f; RabbitMQ一旦向消费者传递了一条消息&#xff0c;便立即将该消息标记为删除。这种情况下&#xff0c;突然有个消…

代码随想录算法训练营day6 | 242.有效的字母异位词、349. 两个数组的交集、202. 快乐数、1.两数之和

文章目录 哈希表键值 哈希函数哈希冲突拉链法线性探测法 常见的三种哈希结构集合映射C实现std::unordered_setstd::map 小结242.有效的字母异位词思路复习 349. 两个数组的交集使用数组实现哈希表的情况思路使用set实现哈希表的情况 202. 快乐数思路 1.两数之和思路 总结 今天是…

OpenCV 遍历Mat,像素操作,使用TrackBar 调整图像的亮度和对比度 C++实现

文章目录 1.使用C遍历Mat,完成颜色反转1.1 常规遍历方式1.2 迭代器遍历方式1.3指针访问方式遍历&#xff08;最快&#xff09;1.4不同遍历方式的时间对比 2.图像像素操作&#xff0c;提高图像的亮度3.TrackBar 进度条操作3.1使用TrackBar 调整图像的亮度3.2使用TrackBar 调整图…