当前位置: 首页 > news >正文

前端下载文件或者图片方式,window.open或者a标签形式

首先分别讲一下下载文件的方式都有哪些

1.通过a标签的方式下载文件

<a href="http://www.baidu.com" download="baidu.html">下载</a>

我们点击下载,发现是跳转到了百度的首页,并没有真的下载文件。

因为a标签下载只能下载同源的文件;如果是跨域的文件,比如图片、音视频等媒体文件等都无法使用上面的a标签方式下载。

上面的代码是直接通过书写a标签来实现文件下载;我们也可以通过js来实现,代码如下:

const a = document.createElement('a')
a.href = 'http://www.baidu.com'
a.download = 'baidu.html'
a.click()

效果和上面的一样,都是跳转到百度的首页,没有下载文件。

这里的重点是a标签的download属性,这个属性是HTML5新增的。

它的作用是指定下载的文件名,如果不指定,那么下载的文件名就会根据请求内容的Content-Disposition来确定,如果没有Content-Disposition,那么就会使用请求的URL的最后一部分作为文件名。

2. 使用 window.open 下载

上面使用a标签的案例也可以通过window.open来实现,效果是一样的,代码如下:

window.open('http://www.baidu.com', '_blank')

这里的_blank是指定用浏览器新窗口打开链接;如果不指定,那么就会在当前页面打开。

同样a标签的download属性也是可以使用的,代码如下:

window.open('http://www.baidu.com', '_blank', 'download=baidu.html')

当然这种方式也是有缺陷的,对比于a标签,window.open方式不能下载.html.htm.xml.xhtml等文件;因为这些文件会被当成html文件来处理,所以会直接在当前页面打开。

同样也不能下载跨域的文件,这个是window.open 实现下载原理决定的。

3. XMLHttpRequest

这种方式就是我们常说的ajax下载,包括AxiosFetch等,代码如下:

const xhr = new XMLHttpRequest()
xhr.open('GET', 'http://www.baidu.com')
xhr.send()xhr.onload = function () {const blob = new Blob([xhr.response], { type: 'text/html' })const a = document.createElement('a')a.href = URL.createObjectURL(blob)a.download = 'baidu.html'a.click()
}

这里关于XMLHttpRequest相关的知识就不做展开了,只讲和文件下载相关的部分。

上面代码主要的逻辑是当我们的请求成功后,我们会拿到响应体Response,这个Response就是我们要下载的内容。

然后我们把它转换成Blob对象,通过URL.createObjectURL来创建一个URL,最后使用a标签的download属性来实现文件下载。

4.Blob 对象

下面是MDN对Blob对象的定义:

Blob对象表示一个不可变、原始数据的类文件对象。

Blob的数据可以按文本或二进制的格式进行读取,也可以转换成ReadableStream来用于数据操作。

Blob表示的不一定是JavaScript原生格式的数据。

File接口基于Blob,继承了Blob的功能并将其扩展以支持用户系统上的文件。

Blob对象是html5新增的对象,它的作用是用来存储二进制数据的,比如图片、视频、音频等,它的使用方法如下:

/*** @param {Array} array 二进制数据* @param {Object} options 配置项* @param {String} options.type 文件类型,它代表了将会被放入到 blob 中的数组内容的 MIME 类型。* @param {String} options.endings 用于指定包含行结束符\n的字符串如何被写入。默认为transparent,表示不会修改行结束符。还可以指定为native,表示会将\n转换为\r\n。*/
const blob = new Blob([], { type: '' })

Tips:需要关注的是type属性,默认情况下, Blob对象是没有type属性的,那么这个Blob就是一个无类型的Blob ,文件不会损毁,但是无法被正常识别。

5.URL.createObjectURL

下面是MDN对 URL.createObjectURL方法的定义: 

URL.createObjectURL()静态方法会创建一个DOMString,其中包含一个表示参数中给出的对象的URL。

这个URL的生命周期和创建它的窗口中的document绑定。

这个新的URL对象表示指定的File对象或Blob对象。

这个方法是用来创建一个URL的,它的作用是把一个Blob对象转换成一个URL,这个URL可以用来下载文件,也可以用来预览文件,代码如下:

const url = URL.createObjectURL(blob)

这里需要注意的是,这个URL的生命周期和创建它的窗口中的document绑定。

也就是说,当我们的document被销毁后,这个URL就会失效,所以我们需要在合适的时机销毁它。

代码如下:

URL.revokeObjectURL(url)

回到我们刚才下载的问题,我们是通过Blob对象来解决,但是我们的type属性是写死的,如果在文件类型是确定的情况下是没问题的。

但是如果这个接口就是下载文件的接口,文件可能是各种类型的,我们应该怎么处理?

这里的没有正确答案,第一个可以和接口提供者进行协商,协商方案是不确定的;第二就是通过Response的header来获取文件的type,也是我们要讲的:

const type = response.headers['content-type']
const blob = new Blob([response.data], { type })

这里我们通过Response的header来获取type,然后再创建Blob对象,这样就可以正确的下载文件了。

其实content-type也可能是application/octet-stream,这个时候我们就需要通过file-type来获取文件的type了。

下面的代码是通过file-type来获取文件的type:

import {fileTypeFromStream} from 'file-type';const type = await fileTypeFromStream(response.body);
const blob = new Blob([response.data], { type })

 

6. 总结

上面的方案这么多,其实最终还是落到a标签上,所以不管是通过浏览器的内置行为进行下载,还是通过ajax进行下载,文件下载的最终还是浏览器的行为。

我项目中遇到的需求如下:

首先window.open(URL)的这种方式和a标签方式一样对于pdf和图片都会打开文件,而并非直接下载,那么当然如果自动打开pdf或者图片,鼠标右击图片或者pdf右上角也会有下载入口。但是如果说需求是点击按钮直接下载文件,那么需要采取获取文件流然后拿到文件流通过a标签下载这种当时,当然获取文件流可以前端去做也可以后端做。

本次需求是通过oss的URL来下载文件。那么我选择前端去做获取文件二进制流。

const downFile = (fileUrl) => {console.log(fileUrl); // fileUrl是oss的url字符串// ********* 方式一 ************// window.open(fileUrl)  //window.open的方式// ********* 方式二 ************// let a = document.createElement("a")  //直接a标签的方式// a.download = 'aaa'// // a.href = window.URL.createObjectURL(blob)// a.href = fileUrl// a.click()// a.remove()// ********* 方式三 ************//直接下载文件并且前端获取文件二进制流const xhr = new XMLHttpRequest();xhr.open('GET', fileUrl, true);xhr.responseType = 'blob'; // 获取文件blob数据xhr.onload = function () {if (xhr.status !== 200) {ElMessage({type: 'error',message: `下载出现错误`,})return;}const newUrl = window.URL.createObjectURL(xhr.response); // 生成一个可用的临时urlconst a = document.createElement('a'); // 生成a标签调用点击事件a.setAttribute('href', newUrl);a.setAttribute('target', '_blank');a.setAttribute('download', fileName); // 自定义文件名document.body.appendChild(a);a.click();document.body.removeChild(a);};xhr.send();
}

感谢这位作者的分享,收获良多,特此记录。

https://juejin.cn/post/7254143696483991611 

相关文章:

前端下载文件或者图片方式,window.open或者a标签形式

首先分别讲一下下载文件的方式都有哪些 1.通过a标签的方式下载文件 <a href"http://www.baidu.com" download"baidu.html">下载</a> 我们点击下载&#xff0c;发现是跳转到了百度的首页&#xff0c;并没有真的下载文件。 因为a标签下载只能…...

webpack配置scss loader

国内GPT站点&#xff1a;https://www.atalk-ai.com 在 Webpack 中配置 sass-loader 用于处理 .scss 文件通常涉及以下步骤&#xff1a; 安装必要的依赖&#xff1a; 你需要安装 sass-loader&#xff0c;以及 sass 本身&#xff08;sass 是 node-sass 的替代品&#xff0c;更快且…...

k8s有状态部署mysql主从(local pv持久化)

1、修改自己对应的命名空间 2、local pv的方式必须先创建好目录在给权限 3、sts部署文件密码都要修改好在部署 yaml资源文件如下&#xff1a; #配置mysql的root密码再部署&#xff0c;如果部署了在修改root密码就会失败&#xff0c;必须在初始化就把root密码修改好 #部署采…...

下载并安装anaconda和VScode,配置虚拟环境,并使用VScode运行代码

文章目录 前言软件下载Anaconda下载VScode下载 软件安装Anaconda安装Vscod安装 配置虚拟环境并运行代码Anaconda创建环境VScode使用&#xff0c;运行代码1. 打开代码所在文件夹2. 选择解释器3. 运行代码 总结 前言 运行python代码&#xff0c;需要2个软件如下&#xff1a; Ana…...

拼图 游戏

运行出的游戏界面如下&#xff1a;按住A不松开&#xff0c;显示完整图片&#xff1b;松开A显示随机打乱的图片 User类 package domain;/*** ClassName: User* Author: Kox* Data: 2023/2/2* Sketch:*/ public class User {private String username;private String password;p…...

python循环语句和函数

1.使用for循环打印9*9乘法表 for i in range(1, 10):for j in range(1, i1):print(i, "*", j, "", i*j, end"\t")print()结果&#xff1a; 2.使用while循环打印9*9乘法表 i 1 while i < 10:j 1while j < i1:print(i, "*", j…...

php框架dcat-admin速查笔记

要想灵活的使用dcat-admin框架开发,必须知道框架有哪些类提供给我们使用. 每一个自定义的按钮,弹框,信息展示,小组件都用到特定的类和接口. 常用核心类 Dcat\Admin\Http\Controllers\AdminController 需要继承的公共控制器 Dcat\Admin\Layout\Content 布局核心 Dcat\Admin\Gr…...

【Java】文件I/O-文件内容操作-输入输出流-Reader/Writer/InputStream/OutputStream四种流

导读 在文件I/O这一节的知识里&#xff0c;对文件的操作主要分为两大类&#xff1a; ☑️针对文件系统进行的操作 ☑️针对文件内容进行的操作 上文已经讲了针对文件系统即File类的操作&#xff0c;这篇文章里博主就来带了解针对文件内容的操作&#xff0c;即输入输出流&am…...

rocky8.9配置K8S集群kubernetes,centos同理

注意&#xff01;&#xff01;&#xff01; 虚拟机实验环境不要使用’克隆’&#xff01;&#xff01;&#xff01; 唯一标识冲突&#xff1a;K8S集群中的每个节点都需要具有唯一的标识符&#xff0c;例如节点名称、IP地址、MAC地址等。当克隆虚拟机时&#xff0c;这些唯一标识…...

Linux下的文件IO之系统IO

1. 知识点 读入写出&#xff0c;切记以我们程序为中心向文件或者别的什么东西读入写出&#xff08;输入流输出流&#xff09; 人话就是 文件向我们程序就是读入 程序向文件或者别的什么就是写出 2. open打开文件 open.c /****************************************************…...

iptables防火墙之SNAT与DNAT

1. SNAT SNAT 应用环境:局域网主机共享单个公网IP地址接入Internet (私有IP不能在Internet中正常路由) SNAT原理:源地址转换&#xff0c;根据指定条件修改数据包的源IP地址&#xff0c;通常被叫做源映射。 数据包从内网发送到公网时&#xff0c;SNAT会把数据包的源IP由私网IP…...

Python与设计模式--命令模式

23种计模式之 前言 &#xff08;5&#xff09;单例模式、工厂模式、简单工厂模式、抽象工厂模式、建造者模式、原型模式、(7)代理模式、装饰器模式、适配器模式、门面模式、组合模式、享元模式、桥梁模式、&#xff08;11&#xff09;策略模式、责任链模式、命令模式、中介者模…...

uni-app 自带返回方法onBackPress,返回上一级并且刷新页面内容获取最新的数据

onBackPress 返回上一级并且刷新页面内容获取最新的数据 onBackPress 方法是uinapp自带返回键方法&#xff0c;也就是在app和H5返回键 onBackPress() {setTimeout(() > {uni.switchTab({url: /pages/Users/index,})}, 300)return true}, methods: {}在这里 uni.switchTab…...

python用YOLOv8对图片进行分类

用yolov8的模型进行分类 先上效果图 图片资源 模型下载地址 https://github.com/ultralytics/ultralytics 代码 import matplotlib.pyplot as plt from ultralytics import YOLO from PIL import Image import cv2model YOLO(../ultralytics/yolov8n.pt)# print(model…...

Spring中@DependsOn 使用详解

一、注解源码 Target({ElementType.TYPE, ElementType.METHOD}) Retention(RetentionPolicy.RUNTIME) Documented public interface DependsOn {String[] value() default {}; } 二、基础概念 DependsOn是Spring框架用来指定bean之间依赖关系的注解之一&#xff0c;即可用户类…...

android笔记 SELinux

1.SELinux解错步骤 log信息&#xff1a; 11-20 02:25:12.526 8976 8976 W om.jzzh.setting: type1400 audit(0.0:1316): avc: denied { write } for name"com.jzzh.setting-IWLR9dkz8TWizbNujdTpWw" dev"mmcblk2p15" ino2661 scontextu:r:system_app:s0…...

vue3 keep-alive页面切换报错:parentComponent.ctx.deactivate is not a function

问题&#xff1a; <router-view v-slot"{ Component }"><keep-alive ><component :is"Component" v-if"$route.meta.keepAlive" /></keep-alive><component :is"Component" v-if"!$route.meta.keepA…...

prompt提示

用例生成 # 任务描述 作为一个高级c程序员&#xff0c;需要完成下列功能的gtest测试用例 # 功能描述 给定两个数字型字符串s1和s2,求和&#xff0c;返回值也是字符串 # 接口举例 调用strAdd("123", "132"),输出“255” # 输出要求 - 入参为空串、nu…...

边缘计算网关:智能制造的“智慧大脑”

一、智能制造的崛起 随着科技的飞速发展&#xff0c;智能制造已经成为了制造业的新趋势。智能制造不仅能够提高生产效率&#xff0c;降低生产成本&#xff0c;还能够实现个性化定制&#xff0c;满足消费者多样化的需求。然而&#xff0c;智能制造的实现离不开大量的数据处理和分…...

HNCTF2022Week1 Reverse WP

文章目录 [HNCTF 2022 Week1]超级签到[HNCTF 2022 Week1]贝斯是什么乐器啊&#xff1f;[HNCTF 2022 Week1]X0r[HNCTF 2022 Week1]你知道什么是Py嘛&#xff1f;[HNCTF 2022 Week1]CrackMe[HNCTF 2022 Week1]给阿姨倒一杯Jvav[HNCTF 2022 Week1]Little EndianNSSCTF{Littl3_Endi…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

FastAPI 教程:从入门到实践

FastAPI 是一个现代、快速&#xff08;高性能&#xff09;的 Web 框架&#xff0c;用于构建 API&#xff0c;支持 Python 3.6。它基于标准 Python 类型提示&#xff0c;易于学习且功能强大。以下是一个完整的 FastAPI 入门教程&#xff0c;涵盖从环境搭建到创建并运行一个简单的…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

全球首个30米分辨率湿地数据集(2000—2022)

数据简介 今天我们分享的数据是全球30米分辨率湿地数据集&#xff0c;包含8种湿地亚类&#xff0c;该数据以0.5X0.5的瓦片存储&#xff0c;我们整理了所有属于中国的瓦片名称与其对应省份&#xff0c;方便大家研究使用。 该数据集作为全球首个30米分辨率、覆盖2000–2022年时间…...

数据链路层的主要功能是什么

数据链路层&#xff08;OSI模型第2层&#xff09;的核心功能是在相邻网络节点&#xff08;如交换机、主机&#xff09;间提供可靠的数据帧传输服务&#xff0c;主要职责包括&#xff1a; &#x1f511; 核心功能详解&#xff1a; 帧封装与解封装 封装&#xff1a; 将网络层下发…...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

【C语言练习】080. 使用C语言实现简单的数据库操作

080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

分布式增量爬虫实现方案

之前我们在讨论的是分布式爬虫如何实现增量爬取。增量爬虫的目标是只爬取新产生或发生变化的页面&#xff0c;避免重复抓取&#xff0c;以节省资源和时间。 在分布式环境下&#xff0c;增量爬虫的实现需要考虑多个爬虫节点之间的协调和去重。 另一种思路&#xff1a;将增量判…...

今日学习:Spring线程池|并发修改异常|链路丢失|登录续期|VIP过期策略|数值类缓存

文章目录 优雅版线程池ThreadPoolTaskExecutor和ThreadPoolTaskExecutor的装饰器并发修改异常并发修改异常简介实现机制设计原因及意义 使用线程池造成的链路丢失问题线程池导致的链路丢失问题发生原因 常见解决方法更好的解决方法设计精妙之处 登录续期登录续期常见实现方式特…...