面试官:如何用a标签实现文件下载?(一文带你手撕知识点)

2023-11-19

前言

大家好,今天给大家带来前端小知识:前端利用a标签实现文件(图片)下载,也就是教大家利用a标签或者是 window.open() 来实现下载功能。

常用方式

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

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

方法分析

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

代码实现

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

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

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

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

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

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

二、实现[HTMLCanvasElement]类型图片下载

  1. 需求场景:

    • 注意:此方法只适用[HTMLCanvasElement]类型,[img]不可用此方法
    • 当你需要将如[二维码]之类的图片下载时
  2. 实现代码

    //调用此函数即可
    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(); // 下载之后把创建的元素删除
    };
    
  3. 调用示例:二维码下载

     <div className={style.codeBox}>
       <QRCode
         id="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>
    
  4. 结果示例
    在这里插入图片描述

三、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>
    
  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]);
  // 通过二进制文件创建url
  let url = window.URL.createObjectURL(blob);
  a.href = url;
  a.download = filename;
  a.click();
  // 销毁创建的url
  window.URL.revokeObjectURL(url);
}
----------- 调用 --------------
 <a onClick={() => { download();}}>
下载二维码
</a>

3、未跨域报错

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

在这里插入图片描述


在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

面试官:如何用a标签实现文件下载?(一文带你手撕知识点) 的相关文章

  • Chrome 中的性能问题

    我目前正在从事一个相对较大的项目 使用 AngularJs 构建 应用程序的一部分是一个表单 您可以向其中添加任意数量的页面 不幸的是 添加了很多不必要的垃圾 即表示表单模型的对象可能会变得非常大 在某些时候 Chrome 基本上无法处理它
  • 如何格式化 Highcharts 的 (x,y) 对数据的日期时间

    我的序列化方法会产生如下所示的日期时间字符串 2014 07 09T12 30 41Z 为什么下面的代码不起作用 function container highcharts xAxis type datetime series data x
  • 如何在codeigniter中将上传图片比例限制为16:9?

    这是我用来上传图像的代码 this gt load gt library upload ext pathinfo file name PATHINFO EXTENSION img name now ext imgConfig upload
  • 可以在初始 DOM 解析期间/之前修改 DOM 吗?

    是否可以在初始 DOM 解析期间或之前修改 DOM 或者我是否必须等到 DOM 被解析和构建之后才能与其交互 更具体地说 是否有可能阻止 DOM 中的脚本元素使用用户脚本 内容脚本或 Chrome 或 Firefox 中的类似脚本运行 在解
  • Snap.svg - 停止在可悬停元素的子元素上重新触发悬停事件

    对于一个项目 我使用的 SVG 形状由背景多边形和背景多边形上方的一些文本 我已将其转换为路径 组成 我正在使用 Snap svg 为我的形状设置动画 当我将鼠标悬停在多边形上时 形状应该缩放到特定尺寸 包括其中的所有内容 鼠标移开时 形状
  • 在打字稿中导入 json

    我是 typescript 的新手 在我的项目中 我们使用 typescript2 在我的要求之一中 我需要导入 json 文件 所以我创建了 d ts 文件如下 test d ts declare module json const va
  • Draggable JS Bootstrap 模式 - 性能问题

    对于工作中的项目 我们在 JavaScript 中使用 Bootstrap Modal 窗口 我们想让一些窗口可移动 但我们遇到了 JQuery 的性能问题 myModal draggable handle modal header Exa
  • Bootstrap按钮加载+Ajax

    我正在使用 Twitter Bootstrap 的按钮加载状态 http twitter github com bootstrap javascript html buttons http twitter github com bootst
  • 防止 iOS 键盘在 cordova 3.5 中滚动页面

    我正在使用 Cordova 3 5 和 jQuery mobile 构建 iOS 应用程序 我在大部分应用程序中禁用了滚动功能 但是 当我选择输入字段时 iOS 键盘会打开并向上滚动页面 我不想要这个功能 由于输入足够高 键盘不会覆盖它 我
  • Jquery 数据表列总和

    我只是参考一下这个链接 https datatables net examples advanced init footer callback html了解如何获取 jquery 数据表中的列总计 但我已经完成了一半的项目 我在html页面
  • 不可勾选的单选按钮与专有的复选框

    从 UI 角度来看 是拥有一组具有取消选中功能的单选按钮更好 还是拥有一组独占的复选框 意味着一次只能选中一个 更好 Update 我没想到对此会有如此负面的反应 如果我给出一个更接近其使用方式的示例 也许会有所帮助 我有一个充满数据绑定内
  • Firebase 函数 onWrite 未被调用

    我正在尝试使用 Firebase 函数实现一个触发器 该触发器会复制数据库中的一些数据 我想观看所有添加的内容votes user vote 结构为 我尝试的代码是 const functions require firebase func
  • 正则表达式 - 从 markdown 字符串中提取所有标题

    我在用灰质 https www npmjs com package gray matter 以便将文件系统中的 MD 文件解析为字符串 解析器产生的结果是这样的字符串 n Clean er ReactJS Code Conditional
  • Three.js 各种大小的粒子

    我是 Three js 的新手 正在尝试找出添加 1000 个粒子的最佳方法 每个粒子都有不同的大小和颜色 每个粒子的纹理是通过绘制画布创建的 通过使用粒子系统 所有粒子都具有相同的颜色和大小 为每个粒子创建一个粒子系统是非常低效的 有没有
  • 在 HTML 下拉列表中有一个滚动条

    我正在寻找一种在 HTML 的下拉列表中添加滚动条的方法 这样如果下拉列表包含的内容超过例如 5 项 将出现滚动条以查看其余项 这是因为我将被迫列出一些大清单 过去几个小时我一直在谷歌上搜索它 但没有运气 它需要适用于 IE8 FF 和 C
  • 对于只触及我的工作表的 Google 表格脚本,收到“此应用程序未经验证”

    我正在编写一个 Google Sheets 脚本 我只想访问与 gs 文件关联的同一电子表格中的数据 似乎我应该有权在自己的电子表格中运行脚本 但是每当我运行一个函数时 我都会得到一个This app isn t verified信息 我该
  • 在 Javascript 中连接空数组

    我正在浏览一些代码 我想知道这有什么用处 grid push concat row 根据我的理解 它等同于 grid push row 为什么要大惊小怪 连接 你想使用 concat当您需要展平数组并且没有由其他数组组成的数组时 例如 va
  • Javascript - 水波纹效果

    我需要 JS 上的脚本 它将以 水波纹 样式更改 images html 抱歉 6MB GIF 文件 http fcuunited ru temp listening2 gif http fcunited ru temp listening
  • 用于交互式图形绘制的轻量级 JavaScript 库? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 我有兴趣了解用于绘制交互式图表的最轻量级 javascript 库 我掌握的数据主要是与海洋研究相关的科学数据 我知道一些 jquery
  • 如何用另一个响应替换窗口的 URL 哈希?

    我正在尝试使用替换方法更改哈希 URL document location hash 但它不起作用 function var anchor document location hash this returns me a string va

随机推荐

  • VMware虚拟机安装CentOS7 Linux教程一篇笔记搞定(超详细)

    VMware虚拟机CentOS7教程篇 自己在网上找了好多资源 结果发现都不全面 教完安装CentOS7系统之后就没有下文了 网络配置 虚拟机网络ip修改地址等等都没有 想想自己还是出一篇比较详细的CentOS7安装教程吧 创作不易 感觉对
  • 关于一个大一学生的俄罗斯方块项目分享C#开发,附源码(一)

    本人为一双非大一计科新生 这是我第一篇文章 能力一般 水平有限 能在各位大佬面前弄斧 不胜荣幸 事情是这样的 我寒假买了一个3ds掌机 玩了里面很多游戏 其中最令我着迷的就是俄罗斯方块 说实话以前也玩过 但不知怎么就上瘾了 沉迷于刷分 什么
  • ChatGPT的出现会不会导致底层程序员失业?

    最近这段时间想必和我一样 都被ChatGPT刷屏了 对于这个问题 我尝试问了一下ChatGPT 它是这样说的 没错 上面的内容是ChatGPT自己 给出的回答 答案当然是 不会 程序员的核心不在于实现一个功能甚至不在于写出代码 而在于编码思
  • 数据库综合练习

    下图分别是练习中的教师表 学生表 成绩表 科目表 练习如下 1 查询 c001 课程比 c002 课程成绩高的所有学生的学号 方法一 使用自连接select c sno 学号from sc cinner join sc t on c sno
  • JNA模拟复杂的C类型——Java映射char*、int*、float*、double*

    文章目录 引言 Java Native Type Conversions Java和C基本类型指针对应关系 Pointer的具体用法 引言 最近项目在用Java调用C写的一些三方库 没办法直接调 用Java封装一下C的接口 这就少不了要用到
  • android 防止反编译 安全加固技术

    先说下加固技术发展历史 基础加固技术 1 代码混淆 proguard 2 签名比对 3 NDK so 库动态使用 第一代加固技术 动态加载 包括第一代加壳技术 落地加载 第二代加固技术 不落地加载 第三代加固技术 指令抽离 第四代加固技术
  • Jmeter(十九) - 从入门到精通 - JMeter监听器 -上篇(详解教程)

    1 简介 监听器用来监听及显示JMeter取样器测试结果 能够以树 表及图形形式显示测试结果 也可以以文件方式保存测试结果 JMeter测试结果文件格式多样 比如XML格式 CSV格式 默认情况下 测试结果将被存储为xml格式的文件 文件的
  • SSL/TLS协议运行机制的概述

    http www ruanyifeng com blog 2014 02 ssl tls html 一 作用 不使用SSL TLS的HTTP通信 就是不加密的通信 所有信息明文传播 带来了三大风险 1 窃听风险 eavesdropping
  • xml命名规则

    Android开发 布局xml文件命名注意事项 不能包含任何大写字母 2012 02 22 14 49 22 转载 标签 android xml 文件 it 分类 Android开发 在开发Android应用时 会接触到布局文件 一般在 工
  • 高德地图报错 TypeError: AMap.Geocoder is not a constructor

    地址逆解析插件 this geoCoder new AMap Geocoder city 010 城市设为北京 默认 全国 radius 1000 范围 默认 500 extensions all 出现这个报错可以添加 AMap plugi
  • 【Python网络蜘蛛】:基础 - HTTP基本原理

    文章目录 1 1 HTTP基本原理 1 URI和URL 2 HTTP和HTTPS 3 HTTP请求过程 4 请求 5 响应 1 1 HTTP基本原理 1 URI和URL URI为统一资源标识符 URL为统一资源定位符 举个例子理解 http
  • 最简单的方式来理解阻抗、反射和端接

    1 阻抗失配与反射 在深入学习电磁场之后 就觉得高中物理老师不应该用水流来比喻电流 结果到了自己去和别人讲阻抗反射 发现用水来做比喻还是很方便轻松的 所以之前在电源滤波的系列文章中 高速先生就多次请 水 来友情出演 这不 欢迎我们的 水 小
  • Simulink仿真模型中的常数符号赋值

    对模型中的参数或者是常数符号赋值可以通过下面两种方法 在MATLAB的命令行中直接赋值 然后再运行仿真模型 如下图 在file gt model properties的initFcn 中进行设置
  • AI芯片,是噱头还是趋势?

    随着AlphaGo的诞生 深度学习 日益普及 人工智能开始从智能化工具向智能机器进军 原有的MCU已无法满足深度学习的高速海量数据运算要求 AI芯片便应运而生 如今嵌入式芯片领域正面临AI芯片的新一轮机遇 那么在AI成为风口的当下 AI芯片
  • 2022年高级性能测试岗面试题【面试必看】

    昨天一个前同事找我 问有没有性能测试岗位的面试题 正好之前帮业务团队加面过几次性能测试岗位的候选人 我将面试时候会问的一些问题以及要考察的点列了出来 供大家参考 一 介绍下最近做过的项目 背景 预期指标 系统架构 场景设计及遇到的性能问题
  • oobabooga-text-generation-webui可能是最好的语言模型启动器(包含手把手安装教程)

    原文 oobabooga text generation webui可能是最好的语言模型启动器 包含手把手安装教程 哔哩哔哩 引言 问 oobabooga是什么 oobabooga text generation webui是一个用于运行类
  • HeadFirst 设计模式学习笔记10——MVC分析

    1 M V C Model View Controller 模式 视图 控制器 这是一种范型 模型对象正是应用系统存在的理由 你设计的对象 包含了数据 逻辑和其他在你的应用领域创建定制的类 视图通常是控件 用来显示和编辑 控制器位于二者中间
  • 3.3 C++多继承与虚基类

    书接上回 继承存在二义性 上图中 A是虚基类 virtual的继承方式就是虚继承 参考下文章 C 虚继承和虚基类详解 知乎 zhihu com
  • apache和iis文件解析漏洞原理及修复

    Apache文件解析漏洞是指攻击者可以利用Apache服务器的文件解析功能 通过构造特殊的URL 访问服务器上的敏感文件 从而获取服务器上的敏感信息 IIS文件解析漏洞是指攻击者可以利用IIS服务器的文件解析功能 通过构造特殊的URL 访问
  • 面试官:如何用a标签实现文件下载?(一文带你手撕知识点)

    前言 大家好 今天给大家带来前端小知识 前端利用a标签实现文件 图片 下载 也就是教大家利用a标签或者是 window open 来实现下载功能 文章目录 前言 常用方式 方法分析 代码实现 常用方式 a href url 下载 a a标签