前端实现下载的触发机制,一篇文章搞定下载(文件下载,图片下载,截屏下载)

本文主要是介绍前端实现下载的触发机制,一篇文章搞定下载(文件下载,图片下载,截屏下载),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

      • 一、下载方式
        • 1.浏览器下载
        • 2.a标签触发下载
          • 什么是base64
          • 自定义下载文件名
      • 二、实战下载
        • 1.文件下载
        • 2.图片下载
        • 3.截屏下载(解决HTML2cavas截屏空白问题)

一、下载方式

一般来说,前端下载,一般分为利用浏览器下载,和a标签触发下载

1.浏览器下载

有时候我们会发现一张图片的路径如果直接输入在浏览器地址栏中就会直接触发下载

例如下面图片

http://webond.tpddns.cn:8823/facility/tempImage.json?path=upload/196afac1-3e44-47df-910b-8783a9807f00.png

但有些图片放入浏览器的地址栏却并没有触发下载,而是在也浏览器中出现图片预览效果

例如:

https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70

探求其原因,我们分别查看了2者了请求头

发现能触发下载的图片请求头存在该属性Content-Disposition: attachment

在这里插入图片描述

后端实现下载

浏览器下载,本质其实是后端在返回的响应头中添加

Content-Disposition:attachment; filename=’下载的文件名‘

那么只要是在浏览器地址栏中访问就能直接触发下载,

form表单下载

我们常用form表单,将下载的url在一个iframe中打开,来触发下载

2.a标签触发下载

对于上述这种存在下载头的url,使用a标签也能触发下载,(同样也是通过浏览器下载,如果没有下载头,a标签会预览该图片)

<a herf='url' download='下载的文件名' /> 

a标签触发下载,一种是上面的带下载头的,还有2种 dataUrl(base64), 和 blobUrl(流),这2种也能直接触发下载,也是用来实现纯前端下载的方式,如前端构建excel,截屏等,然后转换成blobUrl实现下载,对于base64想必大多数人都有疑惑,

什么是base64

基于64个可打印字符来表示二进制数据,在HTTP环境下传递较长的标识信息

简单说就是一串有内容的编码,例如在html中,使用base64的图片,将不会加载请求,因为这串编码就是这张图片,弊端就是浏览器也不会缓存这张图片,因为不是远程加载 的图片

如下:上传文件并转换为base64

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title>
</head><body><input type="file" id='fileId'>
</body>
<script>// 上传图片转换成base64let upDOM = document.getElementById('fileId')upDOM.addEventListener('change', (e) => {console.log(e)console.log(upDOM.files[0])var reader = new FileReader();reader.readAsDataURL(upDOM.files[0]);reader.onload = function (ie) {var Base64Val = this.result;console.log('Base64')console.log(Base64Val)}})
</script>
</html>

通过上述例子,大家可以发现base64很长,所以当图片过大时,使用base64来下载,就会下载失败,因为超出了get的长度限制,所以,大部分情况下,不会直接使用base64,而是进一步转换为blobUrl文件流

// base64转换为blob流function  convertBase64UrlToBlob(base64) {var parts = base64.dataURL.split(";base64,");var contentType = parts[0].split(":")[1];var raw = window.atob(parts[1]);var rawLength = raw.length;var uInt8Array = new Uint8Array(rawLength);for (var i = 0; i < rawLength; i++) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], {type: contentType});}
var blob = convertBase64UrlToBlob (base64)var blobUrl= URL.createObjectURL(blob);
自定义下载文件名

​ 一般情况下,下载的文件名字为后端定义好的文件名,或者是服务器存储的文件名,前端如果要修改,可以利用a标签的download 属性,自己定义下载的文件名,

<a herf='url' download='下载的文件名' />

但要注意一点,能使用download修改名字,要么是同源,要么只能是dataUrl 和bolbUrl,否则无法修改下载的名字

二、实战下载

1.文件下载

一般类似exsel这类下载文件,是需要给后台提交数据来下载的,一般也为post接口,对于这样的下载,

第一种方式使用表单提交 后台也需要接受的是formdata数据

如果页面有现有的表单

form表单下载

没有就用js创建一个隐形的form来提交表单

第二种方式还是使用ajax 后台接收正常的json即可

使用ajax是无法直接下载的,请求成功后,后台会返回一个文件流

看见会是这样的乱码但没什么影响的
在这里插入图片描述

request 为引入的封装好的axios

下面有几个点需要注意

1.是要定义响应的type ,responseType: “arraybuffer”,告诉服务器需要返回一个buffer,不然下载下来很可能 是乱码
在这里插入图片描述

2.我们需要在返回的header把名字取下来,

const fileName = res.headers['content-disposition'].split('=')[1]
//有时候,后端定义的fileName,无效,下载下来还是服务器存储的名字

​ 但是会发现明明header里面有就是取不到Content-Disposcition,

这个是响应头Access-Control-Expose-Headers规定的可以暴露给外部的header

MDN

默认情况下,只有七种 simple response headers (简单响应首部)可以暴露给外部:

  • Cache-Control
  • Content-Language
  • Content-Length
  • Content-Type
  • Expires
  • Last-Modified
  • Pragma

如果想要让客户端可以访问到其他的首部信息,可以将它们在 Access-Control-Expose-Headers 里面列出来。

所以后端只需要配置

response.setHeader("Access-Control-Expose-Headers","Content-Disposcition")

在这里插入图片描述

  function exportFile(url,data){request({//告诉服务器需要返回一个buffer,不然下载下来很可能		是乱码responseType: "arraybuffer",url: url,method: 'post',data: data}).then(res=>{const content = res.data//转换成blob对象const blob = new Blob([content],{ type: 'application/vnd.ms-excel;charset=utf-8' })//获取文件名字const fileName = res.headers['content-disposition'].split('=')[1]const elink = document.createElement('a')elink.download = decodeURI(fileName)elink.style.display = 'none'console.log(res);//生成blobUrlelink.href = URL.createObjectURL(blob)document.body.appendChild(elink)elink.click()URL.revokeObjectURL(elink.href) // 释放URL 对象document.body.removeChild(elink)})}
2.图片下载

如果是图片流,下载方式同上

但大多数时候,是使用一个url来下载

a href="http://webond.tpddns.cn:8823/facility/tempImage.json?path=upload/196afac1-3e44-47df-910b-8783a9807f00.png" download="修改的名字.png">点击</a>

上面提到过 需要后端设置下载头才能触发,但是因为不是同源无法修改名字

image-20210527152922083

但如果想自定义名字,同时也不需要后端设置下载头呢

这个时候我们就需要利用cavas转换一下,

tips注意 cavas,必须要跨越的图片,否则画出来就是空白,同时后台需要设置跨越 指定域名或者*,不然会报跨越的错误,同时图片也无法加载

image-20210527153736217

img.crossOrigin = "Anonymous";  //设置图片跨越,没有跨越cavas会被污染无法画出
     // 转换为base64function    convertUrlToBase64(url) {return new Promise(function (resolve, reject) {var img = new Image();//设置图片跨越,没有跨越cavas会被污染无法画出img.crossOrigin = "Anonymous";img.src = url;img.onload = function () {var canvas = document.createElement("canvas");canvas.width = img.width;canvas.height = img.height;var ctx = canvas.getContext("2d");ctx.drawImage(img, 0, 0, img.width, img.height);var ext = img.src.substring(img.src.lastIndexOf(".") + 1).toLowerCase();//转换为base64var dataURL = canvas.toDataURL("image/" + ext);var base64 = {dataURL: dataURL,type: "image/" + ext,ext: ext};resolve(base64);};});}
   // base64转换为blob流function    convertBase64UrlToBlob(base64) {var parts = base64.dataURL.split(";base64,");var contentType = parts[0].split(":")[1];var raw = window.atob(parts[1]);var rawLength = raw.length;var uInt8Array = new Uint8Array(rawLength);for (var i = 0; i < rawLength; i++) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], {type: contentType});}
  // 判断浏览器function  myBrowser() {var userAgent = navigator.userAgent; //取得浏览器的userAgent字符串if (userAgent.indexOf("OPR") > -1) {return "Opera";} //判断是否Opera浏览器 OPR/43.0.2442.991if (userAgent.indexOf("Firefox") > -1) {return "FF";} //判断是否Firefox浏览器  Firefox/51.0if (userAgent.indexOf("Trident") > -1) {return "IE";} //判断是否IE浏览器 Trident/7.0; rv:11.0if (userAgent.indexOf("Edge") > -1) {return "Edge";} //判断是否Edge浏览器 Edge/14.14393if (userAgent.indexOf("Chrome") > -1) {return "Chrome";} // Chrome/56.0.2924.87if (userAgent.indexOf("Safari") > -1) {return "Safari";} //判断是否Safari浏览器 AppleWebKit/534.57.2 Version/5.1.7 Safari/534.57.2}

下载图片

 var url = 'https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70'var that = thisvar fileName = '自定义的名字'convertUrlToBase64(url).then(function (base64) {console.log(base64);// 图片转为base64returnvar blob = that.convertBase64UrlToBlob(base64); // 转为blob对象// 下载if (that.myBrowser() == "IE") {window.navigator.msSaveBlob(blob, fileName + ".png");} else if (that.myBrowser() == "FF") {window.location.href = url;} else {var a = document.createElement("a");a.download = fileName;a.href = URL.createObjectURL(blob);document.body.appendChild(a)a.click();URL.revokeObjectURL(a.href) // 释放URL 对象document.body.removeChild(a)}});

将上面几个代码和在一起就是完整的转换下载

3.截屏下载(解决HTML2cavas截屏空白问题)

有些时候,我们需要对图片进行处理拼接等,这个时候需要用到截屏,我们可以使用插件html2cavas,来做到截屏效果

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script><style>#content {background: red;display: flex;justify-content: center;align-items: center;width: 500px;height: 500px;}#capture{margin-left: 20px;width: 500px;height: 500px;}div{float: left;}img {width: 90%;height: auto;}</style>
</head><body><div id="content"><img src="https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70"alt=""></div><div id="capture"><p>截屏的图</p></div><button onclick="capture()">截屏</button>
</body></html>
<script>function capture(data) {const el = document.getElementById('content')html2canvas(el).then(canvas => {const imgUrl = canvas.toDataURL("image/png"); // 获取生成的图片的url console.log('imgUrl');console.log(imgUrl);var img = new Image();img.src = imgUrl;document.getElementById('capture').appendChild(img)})}
</script>

在这里插入图片描述

但是发现并没有把图片截取下来,原因就是上面说的图片没跨域无法在cavas上展现

我们需要3点配置,

1.图片上设置跨域crossorigin=“anonymous”

<img crossorigin="anonymous" src=''/>

2.html2cavas 跨域useCORS:true

html2canvas(el,{useCORS:true})

3.后台配置跨域头
在这里插入图片描述

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script><style>#content {background: red;display: flex;justify-content: center;align-items: center;width: 500px;height: 500px;}#capture {margin-left: 20px;width: 500px;height: 500px;}div {float: left;}img {width: 90%;height: auto;}</style>
</head><body><div id="content"><!--  crossorigin="anonymous" 配置图片跨域 --><img crossorigin="anonymous" src="https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70"alt=""></div><div id="capture"><p>截屏的图</p></div><button onclick="capture()">截屏</button>
</body></html>
<script>function capture(data) {const el = document.getElementById('content')// useCORS 配置html2canvas跨越html2canvas(el,{useCORS:true}).then(canvas => {const imgUrl = canvas.toDataURL("image/png"); // 获取生成的图片的url console.log('imgUrl');console.log(imgUrl);var img = new Image();img.src = imgUrl;document.getElementById('capture').appendChild(img)})}
</script>

在这里插入图片描述

如果觉得默认截图过小,或者需要其他配置参考文档配置

html2cavas

下面就是完整截屏下载代码

<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><title>Document</title><script src="https://cdn.bootcdn.net/ajax/libs/html2canvas/0.5.0-beta4/html2canvas.js"></script><style>#content {background: red;display: flex;justify-content: center;align-items: center;width: 500px;height: 500px;}#capture {margin-left: 20px;width: 500px;height: 500px;}div {float: left;}img {width: 90%;height: auto;}</style>
</head><body><div id="content"><!--  crossorigin="anonymous" 配置图片跨域 --><img crossorigin="anonymous"src="https://img-blog.csdnimg.cn/2021052711301061.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21hcmVuZHU=,size_16,color_FFFFFF,t_70"alt=""></div><div id="capture"><p>截屏的图</p></div><button onclick="capture()">截屏</button>
</body></html>
<script>var that = thisfunction capture(data) {const el = document.getElementById('content')// useCORS 配置html2canvas跨越html2canvas(el, {useCORS: true}).then(canvas => {const imgUrl = canvas.toDataURL("image/png"); // 获取生成的图片的url console.log('imgUrl');console.log(imgUrl);var img = new Image();img.src = imgUrl;document.getElementById('capture').appendChild(img)var blob = this.convertBase64UrlToBlob(imgUrl)const name = '捕获的图片.png'var a = document.createElement("a");a.download = decodeURI(name);a.href = URL.createObjectURL(blob);document.body.appendChild(a)a.click();URL.revokeObjectURL(a.href) // 释放URL 对象document.body.removeChild(a)})}// 转换成blob对象function convertBase64UrlToBlob(base64) {var parts = base64.split(";base64,");var contentType = parts[0].split(":")[1];var raw = window.atob(parts[1]);var rawLength = raw.length;var uInt8Array = new Uint8Array(rawLength);for (var i = 0; i < rawLength; i++) {uInt8Array[i] = raw.charCodeAt(i);}return new Blob([uInt8Array], {type: contentType});}
</script>

这篇关于前端实现下载的触发机制,一篇文章搞定下载(文件下载,图片下载,截屏下载)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/641946

相关文章

python使用Akshare与Streamlit实现股票估值分析教程(图文代码)

《python使用Akshare与Streamlit实现股票估值分析教程(图文代码)》入职测试中的一道题,要求:从Akshare下载某一个股票近十年的财务报表包括,资产负债表,利润表,现金流量表,保存... 目录一、前言二、核心知识点梳理1、Akshare数据获取2、Pandas数据处理3、Matplotl

分布式锁在Spring Boot应用中的实现过程

《分布式锁在SpringBoot应用中的实现过程》文章介绍在SpringBoot中通过自定义Lock注解、LockAspect切面和RedisLockUtils工具类实现分布式锁,确保多实例并发操作... 目录Lock注解LockASPect切面RedisLockUtils工具类总结在现代微服务架构中,分布

Java使用Thumbnailator库实现图片处理与压缩功能

《Java使用Thumbnailator库实现图片处理与压缩功能》Thumbnailator是高性能Java图像处理库,支持缩放、旋转、水印添加、裁剪及格式转换,提供易用API和性能优化,适合Web应... 目录1. 图片处理库Thumbnailator介绍2. 基本和指定大小图片缩放功能2.1 图片缩放的

Python使用Tenacity一行代码实现自动重试详解

《Python使用Tenacity一行代码实现自动重试详解》tenacity是一个专为Python设计的通用重试库,它的核心理念就是用简单、清晰的方式,为任何可能失败的操作添加重试能力,下面我们就来看... 目录一切始于一个简单的 API 调用Tenacity 入门:一行代码实现优雅重试精细控制:让重试按我

Redis客户端连接机制的实现方案

《Redis客户端连接机制的实现方案》本文主要介绍了Redis客户端连接机制的实现方案,包括事件驱动模型、非阻塞I/O处理、连接池应用及配置优化,具有一定的参考价值,感兴趣的可以了解一下... 目录1. Redis连接模型概述2. 连接建立过程详解2.1 连php接初始化流程2.2 关键配置参数3. 最大连

Python实现网格交易策略的过程

《Python实现网格交易策略的过程》本文讲解Python网格交易策略,利用ccxt获取加密货币数据及backtrader回测,通过设定网格节点,低买高卖获利,适合震荡行情,下面跟我一起看看我们的第一... 网格交易是一种经典的量化交易策略,其核心思想是在价格上下预设多个“网格”,当价格触发特定网格时执行买

python设置环境变量路径实现过程

《python设置环境变量路径实现过程》本文介绍设置Python路径的多种方法:临时设置(Windows用`set`,Linux/macOS用`export`)、永久设置(系统属性或shell配置文件... 目录设置python路径的方法临时设置环境变量(适用于当前会话)永久设置环境变量(Windows系统

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

Spring Security 单点登录与自动登录机制的实现原理

《SpringSecurity单点登录与自动登录机制的实现原理》本文探讨SpringSecurity实现单点登录(SSO)与自动登录机制,涵盖JWT跨系统认证、RememberMe持久化Token... 目录一、核心概念解析1.1 单点登录(SSO)1.2 自动登录(Remember Me)二、代码分析三、

PyCharm中配置PyQt的实现步骤

《PyCharm中配置PyQt的实现步骤》PyCharm是JetBrains推出的一款强大的PythonIDE,结合PyQt可以进行pythion高效开发桌面GUI应用程序,本文就来介绍一下PyCha... 目录1. 安装China编程PyQt1.PyQt 核心组件2. 基础 PyQt 应用程序结构3. 使用 Q