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

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

一、背景

要实现一个下载功能,后端直接返回了一个图片的地址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;验证模型…

Sftp和ftp 区别、工作原理

Sftp的工作原理&#xff1a; SFTP的工作原理基于SSH协议&#xff0c;通过加密连接和安全认证来保障文件传输的安全性。 SFTP&#xff08;SSH File Transfer Protocol&#xff09;是一个确保数据在传输过程中安全的协议&#xff0c;它通过为传输的数据提供加密保护和对用户…

Docker重启策略和缩小镜像体积

目录 Docker重启策略 命令格式 命令选项 Docker缩小镜像体积 Docker重启策略 命令格式 docker run --restartno|always|on-failure|unless-stopped .... 命令选项 no&#xff1a;不管容器是正常退出还是异常退出&#xff0c;都不会重启容器。默认策略。always&#xf…

Java面试锦集 之 一、Java基础(1)

一、Java基础&#xff08;1&#xff09; 1.final 关键字的作用&#xff1f; 修饰变量&#xff1a; 一旦被赋值&#xff0c;就不能再被修改&#xff0c;保证了变量值的稳定性。 例&#xff1a; final int NUMBER 10; //之后就不能再改变 NUMBER 的值了。修饰方法&#xff1a;…

图解 HDFS 架构 |读写过程

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

【学习笔记】子集DP

背景 有一类问题和子集有关。 给你一个集合 S S S&#xff0c;令 T T T 为 S S S 的超集&#xff0c;也就是 S S S 所有子集的集合&#xff0c;求 T T T 中所有元素的和。 暴力1 先预处理子集的元素和 A i A_i Ai​&#xff0c;再枚举子集。 for(int s0; s<(1<…

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

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

SpringBoot3 使用虚拟线程

目录 环境 说明 application.properties pom.xml Controller Java 验证 环境 Java Java: graalvm-jdk-21Springboot3.3.1 说明 springboot3.x 打开虚拟线程非常简单&#xff0c;只需添加一行配置信息即可。 spring.threads.virtual.enabled true application.properti…

探索 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;后来寻到了一篇博客…

PyTorch可以用来干嘛?

PyTorch 是一个广泛使用的开源机器学习库&#xff0c;由 Facebook AI Research&#xff08;FAIR&#xff09;开发。它主要用于计算机视觉和自然语言处理等深度学习领域&#xff0c;但也可以应用于许多其他类型的机器学习任务。PyTorch 提供了丰富的功能和灵活的设计&#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站音频和视频分开的原因吧

grub之loongarch架构调试

一 什么是grub GNU GRUB 是一个多重操作系统启动管理器。GNU GRUB是由GRUB&#xff08;GRandUnified Bootloader&#xff09;派生而来。 GRUB最初由Erich Stefan Boleyn 设计和应用&#xff1b; 主流发行版 Fedora、Redhat、Centos、Kylin 等基于RPM包的系统&#xff0c;在最新…

04 ES6中对象的简写

在 ES6 中&#xff0c;对象字面量的书写方式进行了一些简化&#xff0c;使得对象的创建更加简洁。以下是 ES6 中对象简写的几种形式&#xff1a; 属性值缩写&#xff1a; 当对象的属性名和属性值的变量名相同时&#xff0c;可以省略属性值&#xff0c;只写属性名。 // ES5 cons…