# 说明

参考资料:简书的 伴歌知行的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、未跨域报错

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

HTML中的一些细节处理相关推荐

  1. UI设计中的App标签栏中的设计细节

    今天苏州学码思小编总结了一些App标签栏中的设计细节,为学习UI设计的学员提供切实有效的学习方法. 标签栏是app的导航,具有明确的表意功能,其作用是辅助文字来指引用户进行快速导航,具有图形化的符号, ...

  2. 用python的scipy中的odeint来解常微分方程中的一些细节问题(适用于小白)

    用python的scipy中的odeint来解常微分方程中的一些细节问题(适用于小白) 写在前面 最近有些需要解决常微分方程的问题,网上查了很多教程都不是很明晰,便自己研究了一段时间,写一点小白初次接 ...

  3. 超级玛丽中那些不为人知的细节(上)惯性与冲刺

    如果有人让你选择一款代表足以代表一个时代的游戏,你会选择哪一款? 如果是我的话,我一定会选那个水管工,它是世界销量第二高的电子游戏,它两次入选IGN史上游戏百强,它还被<Game Informe ...

  4. PS技巧 如何在磨皮过程中保留更多细节

    PS技巧 如何在磨皮过程中保留更多细节 一般的磨皮方法,皮是磨光了,毛孔也没了,象塑料娃娃,最偷懒的就是Neat Image了,方便到是方便,不过磨的象是大肉蛋.关于磨皮最高级的就数贴皮法,但步骤复杂 ...

  5. 小白科研笔记:理解PointRCNN中的Stage-Two细节

    1. 前言 博客写作的这天是清明节.致敬那些抗击新馆病毒的医护人员. 我的上一篇博客分析了PointRCNN框中中预选3d框的生成和基于区间(对Bin的翻译)的3d框误差函数.讨论了基于区间的3d框误 ...

  6. 总结|ORB_SLAM2源码中字典使用细节

    点击上方"3D视觉工坊",选择"星标" 干货第一时间送达 前言 前段时间,主要对ORB-SLAM2中字典的训练与使用进行了些研究,关于字典的训练之前也写过一篇文 ...

  7. 吐血整理:论文写作中注意这些细节,能显著提升成稿质量

    点击上方"AI遇见机器学习",选择"星标"公众号 重磅干货,第一时间送达 文 | python 编 | 小轶 前言 不知诸位在科研的起步阶段,是否曾有过如下的感 ...

  8. 网络推广——网络推广专员浅析网站建设中少不了对细节的关注

    众所周知,企业网站是企业在互联网中向目标用户群体和搜索引擎展示企业形象进行网络推广营销,随着互联网的逐步发展,越来越多的企业选择在互联网中建设企业网站.但是终归不是所有企业都对网站建设很在行,所以有一 ...

  9. spring中bean的细节之三种创建Bean对象的方式

    <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...

  10. 后端技术:Java编程中忽略这些细节,Bug肯定少不了

    在Java语言的日常编程中,也存在着容易被忽略的细节,这些细节可能会导致程序出现各种Bug. Java语言构建的各类应用程序,在人类的日常生活中占用非常重要的地位,各大IT厂商几乎都会使用它来构建自己 ...

最新文章

  1. 安检x光机原理计算机实现,安检x光机成像原理介绍
  2. matlab统计矩阵元素的出现次数
  3. Linux的编译器vi之最详细介绍
  4. .NET Core 3.0之深入源码理解HttpClientFactory(二)
  5. 面向对象进阶-反射(二)重要知识点
  6. 白话经典算法系列之中的一个 冒泡排序的三种实现
  7. Opencv dnn实现人类性别检测和年龄预测
  8. 云图说|初识云数据库GaussDB(for Cassandra)
  9. Intel 64/x86_64/IA-32/x86处理器 - 指令格式(2) - 8086/16位指令格式概述
  10. php图片发送另一台,PHP从一台服务器将图片发送到另一台服务器并保存
  11. 中兴机顶盒刷机后服务器连接失败,刷机后rec无法进入!!!求助
  12. python加密狗的制作_制作u盘加密狗图文教程
  13. PostgreSQL全文检索
  14. python闰年统计_利用Python写一个闰年计算器和每月天数计算器
  15. win10家庭版 mysql_MySQL下载安装详解(win10家庭版)
  16. 虎牙Java后台实现三次面经
  17. hinet邮箱密码可以破解?
  18. 推荐系统与深度学习(九)——NCF模型原理
  19. bjui框架中用icheck实现单选全选效果
  20. 循证护理教育中的移动辅助同伴评估方法

热门文章

  1. 全连接神经网络的BP算法(BP神经网络模型)与卷积神经网络的BP算法
  2. win7自带tftp服务器,Win7系统开启TFTP服务器的方法
  3. EditorGridPanel 加载问题
  4. PMP培训机构选择五大关键点!看完就会!
  5. jmeter下载及安装配置
  6. html导出excel换行,javascript导出excel或者csv如何让单元格内容换行?
  7. Android 音视频开发(一):PCM 格式音频的播放与采集
  8. PAT乙级------1006~1010附代码及思路
  9. 软件测试理论知识-基本概念
  10. 游戏开发入门(五)游戏动画系统