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

article/2025/9/28 12:38:17

前言

大家好,今天给大家带来前端小知识:前端利用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}><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>
    
  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]);// 通过二进制文件创建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/M4KLr38g.shtml

相关文章

Jquery之遍历元素

J q u e r y Jquery Jquery之遍历元素 使用 e a c h ( ) each() each()方法传入函数两个参数分别为 i n d e x , d o m index,dom index,dom对象。 <body><div>1</div><div>2</div><div>3</div> </body> <script src&quo…

jQuery 遍历数据

在jQuery 中&#xff0c; $.each( )方法主要用于遍历数据&#xff0c;通过该方法&#xff0c;我们可以遍历任何一个对象&#xff0c;比如数组和对象。 语法格式&#xff1a; $.each(object,function(index,ele))示例&#xff1a; &#xff08;1&#xff09;遍历数组的数据 …

jQuery - 元素遍历

前言&#xff1a; 一提到“遍历”,大家一般都能联想到 each() 或者 for()等语法&#xff0c;但是在jQuery中究竟什么是遍历&#xff1f; 什么是遍历&#xff1a; jQuery 遍历&#xff0c;意为"移动"&#xff0c;用于根据其相对于其他元素的关系来"查找&qu…

Jquery-节点遍历4种方法

节点遍历 遍历子元素 遍历同辈元素 遍历前辈元素 其他遍历方法 遍历子元素 children()方法可以用来获取元素的所有子元素 $(selector).children([expr]); 获取<section>的子元素&#xff0c;但不包含子元素的子元素 var $section $("section").childr…

jq遍历元素

jq遍历元素 通过jq遍历元素、并控制一些元素的属性&#xff08;显示/隐藏、value、src等等&#xff09;&#xff0c;是我们在开发之中比较常见的操作&#xff0c;也为我们的业务功能扩宽了方向&#xff0c;接下来我将结合近段时间在工作上的际遇粗略介绍一下一些稍稍复杂的jq遍…

JS 遍历

目录 1. for 数组遍历2. for ... of3. forEach( )4. some( )5. every( )6. filter( )7. map( )8. find( )9. findIndex( )10. reduce( )11. reduceRight( ) 对象遍历1. for ... in2. Object.keys( )3. Object.values( )4. Object.entries( )5. Object.getOwnPropertyNames( ) 1…

数据库——数据字典

数据库——数据字典是什么&#xff1f; 一.数据字典以及使用场景&#xff1a; User表&#xff0c;User主体有很多属性&#xff0c;比如证件&#xff08;身份证、居住证、港澳通行证…&#xff09;地区&#xff08;河北、河南、北京…&#xff09;等&#xff0c;然后表建好了&…

数据库设计--数据字典

数据字典定义 数据字典&#xff08;data dictionary&#xff09;是对于数据模型中的数据对象或者项目的描述的集合&#xff0c;这样做有利于程序员和其他需要参考的人。分析一个用户交换的对象系统的第一步就是去辨别每一个对象&#xff0c;以及它与其他对象之间的关系。这个过…

解决Error: ENOENT: no such file or directory, scandir ‘xxx\node-sass\vendor‘

解决Error: ENOENT: no such file or directory, scandir xxx\node-sass\vendor 前端项目持续部署打包中出现一个奇怪的问题&#xff0c;记录一下。 cnpm install 安装依赖成功 cnpm run build 构建时失败了&#xff0c;错误表示没有 D:\andex\stofrontend\node_modules\node…

Syntax Error: Error: ENOENT: no such file or directory, scandir ‘D:

在使用npm安装node-sass的时候&#xff0c;可能会出现如下的报错&#xff1a; Syntax Error: Error: ENOENT: no such file or directory, scandir D:\work\ 解决方案是执行以下方法&#xff1a; npm rebuild node-sass

扫描dir目录函数之scandir()

scandir: 读取特定的目录数据头文件: dirent.h 函数定义: int scandir(const char *dir, struct dirent ***namelist, int (*select)(const struct dirent *), int (*compar)(const struct dirent**, const struct dirent**)); 说明: scandir()会扫描参数dir指定的目录文件, …

解决Error: ENOENT: no such file or directory, scandir

解决Error: ENOENT: no such file or directory, scandir xxx\node-sass\vendor 前端项目持续部署打包中出现一个奇怪的问题&#xff0c;记录一下。 cnpm install 安装依赖成功 npm run build 构建时失败了&#xff0c;错误表示没有 D:\andex\stofrontend\node_modules\nod…

Module build failed: Error: ENOENT: no such file or directory, scandir node_modules\node-sass\vendor

npm install 报错 Module build failed: Error: ENOENT: no such file or directory, scandir D:\workspaces\xxx\node_modules\node-sass\vendor npm install node-sass 或者 npm rebuild node-sass 即可 下载完成后项目成功启动。

解决Vue Disconnected from UI server errno: -4058, syscall: ‘scandir‘, code: ‘ENOENT‘,

启动vue ui时出现上述报错 查看powershell中的错误提示 发现问题出在扫描项目时项目中少了某个文件夹 解决方法&#xff1a;手动创建该文件 问题解决

npm安装electron时报Error: EPERM: operation not permitted, scandir.....

刚弄完vue脚手架,准备安装electron写个桌面应用&#xff0c;运行命令vue add electron-builder一直报错 Error: EPERM: operation not permitted, scandir C:\Users\ &#xff0c;百度解释说因为没有权限操作&#xff0c;于是百度试各种方法&#xff0c; 打开黑窗口一遍遍尝试&…

解决“: no such file or directory, scandir ‘..\node_modules\node-sass\vendor“

一、报错信息 二、出现原因 在下载包完成启动项目时出现 Error: ENOENT: no such file or directory, scandir ‘D:…\signpay-admin-new\node_modules\node-sass\vendor’ 三、解决办法 重新下载node-sass包即可 npm rebuild node-sass

解决 no such file or directory, scandir ‘node_modules\node-sass\vendor 报错

运行项目突然报错【no such file or directory, scandir node_modules\node-sass\vendor】这个错误 报错说是找不到node-sass文件路径&#xff0c;最后找到了解决方案 错误截图如下&#xff1a; 重新构建一下npm rebuild node-sass包 npm rebuild node-sass 再直接运行&…

C语言测试。自己实现scandir 函数

在C语言课程的后端&#xff0c;讲完指针和标准文件IO处理&#xff0c;我会做出一个难度较大练习&#xff0c;题目就是&#xff0c; 利用标准的目录处理函数 opendir/readdir/closedir实现类似于 scandir的功能。其中接口要scandir 函数一致。 这个题目看起来简单&#xff0c;实…

5G物联网设备,防止黑客入侵是首要问题

5G IoT设备预计2023年将达到4900万台&#xff0c;研究人员启动了一些程序来防止IoT成为渗透的黑洞。开放标准被认为可以推动物联网设备的互操作性&#xff0c;从而使网络安全软件可以在整个网络中查询设备。许多供应商甚至希望在物联网节点中安装应用程序或代理。毕竟所有移动设…

5G技术在物联网行业的应用

2015年6月&#xff0c;国际电信联盟无线通信部门&#xff08;ITU-R&#xff09;5G 工作组第 22 次会议召开&#xff0c;正式将 5G 命名为 IMT-2020。 什么是5G 5G网络即第五代移动通信网络&#xff0c;数据传输速率远高于以前的蜂窝网络&#xff0c;最高可达10 Gbit/s&#xff…