HTML中的一些细节处理

article/2025/9/13 22:54:51

# 说明

参考资料:简书的 伴歌知行的JS下载图片和文件,防止浏览器直接打开 、夜半修仙,;
CSDN的weixin_3791475的使用a标签下载文件不跳转;
努力学习的汪:洪学习笔记

文章目录

  • # 说明
  • 前端利用a标签实现文件[图片]下载
  • 文件下载常用方式
  • 总结分析
  • Ⅰ-后端设置下载请求的响应头 `Content-Disposition` 强制下载
  • Ⅱ-实现[HTMLCanvasElement]类型图片下载
  • Ⅲ- a标签+download属性
  • Ⅳ-通过接口跨域请求,动态创建a标签,以blob形式下载
      • 1、`fetch`请求
      • 2、`xhr`请求
      • 3、未跨域报错

前端利用a标签实现文件[图片]下载

利用a标签或者是window.open()实现下载

文件下载常用方式

  1. <a href="http://127.0.0.1:3000/upload/hongjilin.png">下载</a> a标签访问文件地址
  2. window.open('http://127.0.0.1:3000/upload/hongjilin.png') 打开文件地址
  3. 后端提供一个接口 /api/download 通过接口返回文件流

浏览器通过请求头Content-Type中的MIME类型(媒体类型,通常称为 Multipurpose Internet Mail ExtensionsMIME 类型,如 :image/jpeg application/pdf)识别数据类型,对相应的数据做出相应处理,对于图像文本等浏览器可以直接打开的文件,默认处理方式就是打开,为了避免浏览器直接打开文件我们需要做一些处理;详情看下方实现部分

总结分析

  1. 所有情况通用的方式: 后端设置下载请求的响应头 Content-Disposition: attachment; filename="filename.jpg"
  • attachment 表示让浏览器强制下载
  • filename 用于设置下载弹出框里预填的文件名
  1. 非跨域情况下 给a标签加上 download 属性,如 <a href="url" download="xxx.png"></a>
  • download 里写文件名 注意后缀 (值非必填)
  1. 通过请求解决跨域问题 动态创建a标签通过blob形式下载,此部分在下方有体现

Ⅰ-后端设置下载请求的响应头 Content-Disposition 强制下载

这是最通用的一种方式 不受跨域和请求方式的影响

Content-Disposition: attachment; 
filename="filename.jpg"

想使用window.open实现强制下载的可以用这种方式

在常规的 HTTP 应答中,该响应头的值表示对响应内容的展现形式

  • inline 表示将响应内容作为页面的一部分进行展示
  • attachment 表示将响应内容作为附件下载,大多数浏览器会呈现一个“保存为”的对话框
  • filename(可选) 指定为保存框中预填的文件名

Ⅱ-实现[HTMLCanvasElement]类型图片下载

想对于HTMLCanvasElement更详细了解 -->点我跳转

  1. 需求场景:
  • 注意:此方法只适用[HTMLCanvasElement]类型,[img]不可用此方法
  • 当你需要将如[二维码]之类的图片下载时
  1. 实现代码
//调用此函数即可
const downCode = (ref) => {const canvas =  document.querySelector(`#${ref}`);downLoad(saveAsPNG(canvas));
};
const saveAsPNG = (canvas) => {return canvas.toDataURL('image/png');
};
const downLoad = (url) => {var oA = document.createElement('a');oA.download = '邀请二维码'; // 设置下载的文件名oA.href = url;document.body.appendChild(oA);oA.click();oA.remove(); // 下载之后把创建的元素删除
};
  1. 调用示例:二维码下载
 <div className={style.codeBox}><QRCodeid="qrid"className={style.code}value={'https://portrait.gitee.com/uploads/avatars/user/2858/8575316_hong-jilin_1611225712.png'}size={165}/><div className={style.codeText}>h5二维码<a onClick={() => downCode('qrid')}>下载</a></div></div>
  1. 结果示例
    在这里插入图片描述

Ⅲ- a标签+download属性

url是同源(同域名、同协议、同端口号)时,这种情况用 a标签加download属性的方式即可,download属性指示浏览器该下载而不是打开该文件,同时该属性值即下载时的文件名;

注意:此方法会导致一个问题,当你下载图片的URL是远程图片url时,将不是下载该文件而是打开该文件

  1. 错误示例代码–>(将远程url换成本地图片url即正确)
	<div className={style.codeText}>小程序码<a download  target='_black' href='https://portrait.gitee.com/uploads/avatars/user/2858/8575316_hong-jilin_1611225712.png?response-content-type=application/octet-stream' >下载二维码</a></div>
  1. 结果:不是下载而是直接打开该url

在这里插入图片描述

Ⅳ-通过接口跨域请求,动态创建a标签,以blob形式下载

当接口请求的跨域问题已经解决时(如Nginx方式),才可以直接通过请求的方式拿到文件流

1、fetch请求

将文件流转为blob格式,再通过a标签的download属性下载

onClick={() => {
// 用fetch发送请求
fetch('https://portrait.gitee.com/uploads/avatars/user/2858/8575316_hong-jilin_1611225712.png').then((res) => {
res.blob().then((blob) => {
const blobUrl = window.URL.createObjectURL(blob);
// 这里的文件名根据实际情况从响应头或者url里获取
const filename = 'hong.jpg';
const a = document.createElement('a');
a.href = blobUrl;
a.download = filename;;
a.click();
window.URL.revokeObjectURL(blobUrl);
});
});
}}

上面通过原生fetch请求,动态生成一个a标签实现文件下载

res.blob() 该方法是Fetch API的response对象方法,该方法将后端返回的文件流转换为返回blob的Promise;blob(Binary Large Object)是一个二进制类型的对象,记录了原始数据信息

URL.createObjectURL(blob) 该方法的返回值可以理解为一个 指向传入参数对象的url 可以通过该url访问 参数传入的对象

  • 该方法需要注意的是,即便传入同一个对象作为参数,每次返回的url对象都是不同的
  • url对象保存在内存中,只有在当前文档(document)被卸载时才会被清除,因此为了更好的性能,需要通过URL.revokeObjectURL(blobUrl) 主动释放

2、xhr请求

模拟发送http请求,将文件链接转换成文件流,然后使用a标签download属性进行下载。

/***************** 下载文件  ************************************** */
function download() {let url ='https://portrait.gitee.com/uploads/avatars/user/2858/8575316_hong-jilin_1611225712.png';let name = 'hong.jpg';// 发送http请求,将文件链接转换成文件流fileAjax(url,function (xhr) {downloadFile(xhr.response, name);},{responseType: 'blob',});
}function fileAjax(url, callback, options) {let xhr = new XMLHttpRequest();xhr.open('get', url, true);if (options.responseType) {xhr.responseType = options.responseType;}xhr.onreadystatechange = function () {if (xhr.readyState === 4 && xhr.status === 200) {callback(xhr);}};xhr.send();
}function downloadFile(content, filename) {window.URL = window.URL || window.webkitURL;let a = document.createElement('a');let blob = new Blob([content]);// 通过二进制文件创建urllet url = window.URL.createObjectURL(blob);a.href = url;a.download = filename;a.click();// 销毁创建的urlwindow.URL.revokeObjectURL(url);
}
----------- 调用 --------------
<a onClick={() => { download();}}>
下载二维码
</a>

3、未跨域报错

当你没解决跨域时使用此方法会有出现下方报错,所以此方法适用已经解决跨域问题的场景

在这里插入图片描述


http://chatgpt.dhexx.cn/article/88cCOd3Z.shtml

相关文章

JAVA中数组和集合的区别

转换 数组转换为集合&#xff1a; Arrays.asList(数组) 示例&#xff1a; 1 2 3 4 5 int[] arr {1,3,4,6,6};//定义一个长度为5数组 Arrays.asList(arr); for(int i0;i<arr.length;i){ System.out.println(arr[i]); } 集合转换为数组&#xff1a; 集合.toArray()…

JAVA中数组和集合的相互转换

数组转集合&#xff1a; 1.遍历&#xff0c;最常用的方法&#xff0c;但是过程会繁琐一点 int arrs[] {1, 2};//1.遍历List<Integer> list new ArrayList<>();for (int ele : arrs) {list.add(ele);}System.out.println(list);2.使用数组工具类的asList()方法 但…

数组与集合的区别及知识拓展

一、数组和集合的区别 1、数组的长度是固定的&#xff0c;一个数组只能存储一种类型的元素&#xff0c;可以存储任意类型。 2、集合的长度是可变的&#xff0c;存储引用数据类型&#xff0c;当存储基本数据类型时需要存储其对应的包装类。 二、知识拓展 1、基本数据类型所对应…

数组和集合的区别及定义方式

数组和集合的定义 一、数组 数组是java语言内置的数据类型&#xff0c;他是一个线性的序列&#xff0c;所有可以快速访问其他的元素&#xff0c;数组和其他语言不同&#xff0c;当你创建了一个数组时&#xff0c;他的容量是不变的&#xff0c;而且在生命周期也是不能改变的&a…

Java的数组与集合

Java的数组与集合 数组1.数组的概念2.数组的定义3.数组的初始化数组静态初始化数组动态初始化数组默认初始化值 4.数组元素访问5.数组的遍历6.数组的内存图JVM的内存图数组的内存图扩展 集合1.集合与数组的比较基本数据类型的包装类 2.集合中的成员方法 数组 1.数组的概念 数组…

数组与集合有什么不同之处

这个问题其实就是一个非常基础的面试题&#xff0c;一般面试官想了解你基础知识方面的掌握时&#xff0c;基本都会问这个问题&#xff0c;尤其是一些&#xff0c;计算机学子毕业之后&#xff0c;如果还是想要从事计算机技术相关的行业时&#xff0c;那么在面试的时候就需要做好…

kotlin数组和集合

一、Kotlin数组 1.对象数组 由Kotlin的main函数的写法&#xff0c;可以看出Kotlin中的对象数组写法与泛型的写法很像。 fun main(args: Array<String>){ } 声明对象数组的三种形式&#xff1a; (1)使用arrayOf函数和指定的数组元素创建数组 //Java写法: String[] p…

Java--数组和集合区别

一、数组 1、Java语言中的数组是一种引用数据类型&#xff1b;不属于基本数据类型 2、数组当中既可以存储“基本数据类型”的数据&#xff0c;也可以存储“引用数据类型”的数据&#xff08;数组既可以存储基本数据类型&#xff0c;又可以存储引用数据类型&#xff0c;基本数…

数组和集合的区别

一、数组声明了它容纳的元素的类型&#xff0c;而集合不声明。 二、数组是静态的&#xff0c;一个数组实例具有固定的大小&#xff0c;一旦创建了就无法改变容量了。而集合是可以动态扩展容量&#xff0c;可以根据需要动态改变大小&#xff0c;集合提供更多的成员方法&#xff…

数组和集合区别

一、数组声明了它容纳的元素的类型&#xff0c;而集合不声明。 二、数组是静态的&#xff0c;一个数组实例具有固定的大小&#xff0c;一旦创建了就无法改变容量了。而集合是可以动态扩展容量&#xff0c;可以根据需要动态改变大小&#xff0c;集合提供更多的成员方法&#xff…

Intellij idea 的tomcat原理讲解

作者: 陈宇超          纪念卓越班的日子 初次用idea的小白可能会很感到很神奇&#xff0c;intellij idea部署web项目在浏览器不需要输入项目名就可以直接访问&#xff0c;很是方便啊。那么 intellij 是如何实现这一功能的呢&#xff1f;在了解其原理之前需要掌握一定的…

Tomcat运行原理

Tomcat服务器本质 Tomcat是运行在JVM中的一个进程。通过处理scoket通信 (Socket) 来运行。Web项目的本质&#xff0c;是一大堆的资源文件和方法。Web项目没有入口方法(main方法)&#xff0c;意味着Web项目中的方法不会自动运行起来。Web项目部署进Tomcat的webapp中&#xff0c…

tomcat原理简要分析,java

tomcat原理 tomcat位置 tomcat实际上是部署在服务器上的&#xff1b; tomcat作用 tomcat服务器是一个Servlet和JSP容器&#xff0c;它响应HTML页面的访问请求。 实际上Tomcat是Apache 服务器的扩展&#xff0c;但运行时它是独立运行的&#xff0c;所以当你运行tomcat 时&#…

谈谈TOMCAT原理和机制

从服务器说起&#xff0c;一台装了操作系统&#xff08;linux、unix、win等等&#xff09;的物理机或者虚拟机不能称之为真正的服务器&#xff0c;因为服务器是能对外界提供服务的计算机&#xff0c;要能成为服务器必须借助其他软件的支持比如:tocmat、apache、IIS、nginx、jet…

Tomcat工作原理

本文以 Tomcat 5 为基础&#xff0c;也兼顾最新的 Tomcat 6 和 Tomcat 4。Tomcat 的基本设计思路和架构是具有一定连续性的。 Tomcat 总体结构 Tomcat 的结构很复杂&#xff0c;但是 Tomcat 也非常的模块化&#xff0c;找到了 Tomcat 最核心的模块&#xff0c;您就抓住了 Tom…

tomcat启动原理

前言 一直在用Tomcat&#xff0c;但是对其启动原理一直没去研究&#xff0c;这里准备去面试&#xff0c;可能会问道。于是总结了下启动原理。完全凭感觉去揣测&#xff0c;没工夫看源码。因此错误之处希望大家批评指正&#xff0c;大家共同进步。我想这也是在忙碌中进步最快的…

深入剖析Tomcat原理

深入剖析Tomcat原理 一、 Tomcat源码部署和运行&#xff08;intellij IDEA&#xff09; 1、下载tomcat源码&#xff0c;以tomcat-8为例 链接: https://tomcat.apache.org/ 2、源码部署到IDEA中 ①创建新的空工程 ②解压源码压缩包到该工程的目录&#xff08;目录名最好是非…

Springboot内置Tomcat原理

SpringBoot的启动主要是通过实例化SpringApplication来启动的&#xff0c;启动过程主要做了以下几件事情&#xff1a;配置属性、获取监听器&#xff0c;发布应用开始启动事件初、始化输入参数、配置环境&#xff0c;输出banner、创建上下文、预处理上下文、刷新上下文、再刷新上…

【springboot】自动整合Tomcat原理

通过前面我们会SpringBoot的自动配置机制、Starter机制、启动过程的底层分析&#xff0c;我们拿一个实际的业务案例来串讲一下&#xff0c;那就是SpringBoot和Tomcat的整合。 我们知道&#xff0c;只要我们的项目添加的starter为&#xff1a;spring-boot-starter-web&#xff…

总结:SpringBoot内嵌Tomcat原理

一、介绍 一般我们启动web服务都需要单独的去安装tomcat&#xff0c;而Springboot自身却直接整合了Tomcat&#xff0c;什么原理呢&#xff1f; 二、原理 SpringBoot应用只需要引入spring-boot-starter-web中这个依赖&#xff0c;应用程序就默认引入了tomcat依赖&#xff0c;其…