前端实现文件导出

news/2024/11/15 18:52:01/文章来源:https://www.cnblogs.com/wyl-1113/p/18371558

在后台管理系统中,我们经常会遇到文件导出这个需求,下面,我将几种常见的导出方式做一个简单的介绍,让大家在以后遇到此类需求时,能够切合实际情况,采取相对合理的方式。

导出目标

文件地址
已经存在服务器上的静态文件,比如用户上传的图片、材料等等。
http://192.168.1.103:3000/imgs/bg.jpg

导出接口
根据用户需求,由后端动态生成的文件,常见的比如导出业务流水表格,数据汇总表格等等。
http://192.168.1.103:3000/api/export

导出方式

image.png

a.download

html5新增的属性

优点:简单。
缺点:ie不支持,并且在跨域时,即使后台设置了允许跨域的响应头,也无法下载,也就是说必须与当前域一致。

// 这里的http://192.168.1.103:3000必须与当前地址栏一致才行
<a href="http://192.168.1.103:3000/imgs/xx.jpg" download />

download属性可以指定文件名(如果content-disposition指定了文件名,以content-disposition为准),也可以为空值,两种情况具体如下:
image.png

ajax + a.download

缺点:ie不支持,blob有内存限制。
优点:避免了单独使用a.download必须与域名一致的问题。

将后台返回的二进制数据,转换成blob,然后利用URL.createObjectURL,创建一个指向内存中blobURL,再使用a标签的download属性进行导出

function useLinkDownload(url, fileName) {const link = document.createElement("a");link.style.display = "none";link.href = url;link.download = fileName;document.body.appendChild(link);link.click();document.body.removeChild(link);
}$.get('http://192.168.1.103:3000/api/export', { responseType: 'blob' }).then(function(res) {// 创建一个指向内存中blob的URLconst objectURL = URL.createObjectURL(res.data);useLinkDownload(objectURL, 'xx.xlsx')URL.revokeObjectURL(objectURL)})

ajax + msSaveBlob

优点:支持ie,这算优点?
缺点:chrome、firefox不支持,blob有内存限制

$.get('http://192.168.1.103:3000/api/export', { responseType: 'blob' }).then(function(res) {navigator.msSaveBlob(res.data, "xx.xlsx");})

content-disposition

优点:兼容性极好。
缺点:需要后台支持。

前端发送请求即可(其他的交给后台),后台响应数据时,按照规范设置content-disposition,需要注意的一点是,不能与ajax组合(使用ajax后,会变成二进制数据流,流的处理被ajax接管)
(此种方式指定的文件名优先级高于a.download

var url = 'http://192.168.1.103:3000/api/export'

content-disposition可以结合以下任一一种方式进行导出:

// a标签function useLink(url) {const link = document.createElement("a");link.style.display = "none";link.href = url;document.body.appendChild(link);link.click();document.body.removeChild(link);
}useLink(url)
// location.hrefwindow.location.href = url;
// window.openwindow.open(url);
// formfunction useFormDownload(url) {const form = document.createElement("form");form.action = url;form.method = "get";form.style.display = "none";document.body.appendChild(form);form.submit();form.remove();
}useFormDownload(url)
// iframe
function useIframeDownload(url) {const iframe = document.createElement("iframe");iframe.src = url;iframe.style.display = "none";document.body.appendChild(iframe);document.body.removeChild(iframe);
}
useIframeDownload(url)

问题

跨域
a.download无效,即使后台设置了Access-Control-Allow-Origin也无效,download的值需要与当前域名一致,ngnix进行转发可以解决。
https://html.spec.whatwg.org/dev/links.html#downloading-resources

大文件
ajax的方式需要用到blob,而blob是有限制的,例如chrome的上限是2GB,所以ajax的方式需要被排除,可选的方式是a.downloadContent-Disposition,这两种方式没有用到blob,所以也没有明确的限制。

iframe存在的问题
在使用a标签或者form时,为了避免在导出时发生页面闪烁现象,我们可以使用targe_self的值来避免,但是当target_self时,如果导出请求失败了,页面会被覆盖掉,用哪种方式可以避免这个问题?
可选的方式为ajaxiframe,这两者都可以避免失败时覆盖掉当前页面,并且ajax还可以告诉用户失败的原因

总结

默认情况下,浏览器面对自身无法打开的文件,都会采取将其保存到本地方式,但是图片、文本文件以及pdf,浏览器会首先尝试将其打开,这在一般情况下是合理的,但当我们的目的是保存而不是打开时,这就会变成一个问题。

上文罗列了几种导出方式以及各自的局限性,综合来看Content-Disposition应该是比较通用的方式,即兼顾了兼容性,也避免了浏览器内存限制。

资料

https://github.com/eligrey/FileSaver.js/wiki/Saving-a-remote-file#using-http-header

原文链接:javascript - 文件导出 - 这好像无法拒绝 - SegmentFault 思否

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/800578.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

JavaScript拆分字符串时产生空字符的原因

问题描述 使用JavaScript的split方法拆分字符串时出现一些空字符串"",尤其是当使用正则表达式作为分隔符的时候。 相关问题javascript正则表达式对字符串分组时产生空字符串组?在上面这个问题中,题主使用正则表达式对字符串进行分割时产生了多个空字符串"&qu…

ASR6601 是一款通用的 Sub-GHz 无线通讯 SoC 芯片

SoC 芯片ASR6601 是一款通用的 Sub-GHz 无线通讯 SoC 芯片 该芯片集成了 Sub-GHz 射频收发器和 32 位的 RISC MCU。Sub-GHz 射频收发器不仅支持 LoRa 调制,还支持 (G)FSK 和 G(MSK) 等调制方式。CPU 为 ARM STAR,工作频率最大支持 48 MHz。此外,该芯片支持 3 x I2C,1 x I2S…

[ABC221H] Count Multiset

题意思路 参考了题解做法。 设 \(f_{i, j}\) 表示填入 \(i\) 个数字,和为 \(j\) 的方案数。 每次可以填入 \(0\),或者将整个数列 \(+1\)。 \(g_{i, j}\) 表示填入 \(i\) 个数字,且这 \(i\) 个数字中没有 \(0\),何为 \(j\) 的方案数。 易得 \(g_{i, j} = f_{i, j - i}\),表…

ModelForm

1.7 ModelForm使用Form创建Form类 + 定义字段 class LoginForm(forms.Form):user = forms.CharField(label="用户名", widget=forms.TextInput)pwd = forms.CharField(label="密码", widget=forms.TextInput)视图def login(request):if request.method == …

深入理解Java对象结构

一、Java对象结构 实例化一个Java对象之后,该对象在内存中的结构是怎么样的?Java对象(Object实例)结构包括三部分:对象头、对象体和对齐字节,具体下图所示1、Java对象的三部分 (1)对象头 对象头包括三个字段,第一个字段叫作Mark Word(标记字),用于存储自身运行时的…

Kyutai 开源对话模型 Moshi;李飞飞空间智能公司已筹集超过 2.3 亿美元丨 RTE 开发者日报

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的新闻」、「有态度的观点」、「有意思的数据」、「有思考的文章」、「有看点的会议」,但内容仅代表编辑的个人观点…

P3224 [HNOI2012] 永无乡

题意思路 用并查集维护连通性,每个集合维护一个平衡树,每次合并两个集合的时候,将一个平衡树的节点一个一个加入到另一个中。 这么做不会超时,每次将小的平衡树拆掉放到大的中,可以证明不会超过 \(O(\log n)\) 次。 总时间复杂度 \(O(n \log ^ 2 n)\)。 代码 #include <…

C#使用HttpWebRequest读取网站内容遭遇503错误

本人多年编程小白,天生编程白痴体质。大家莫见笑。 自己用C#写了一段代码,使用HttpWebRequest,通过SOHU的API接口获取指定股票的交易信息。 该段代码一直运行正常。最近开始报错。 详细信息如下: System.Net.WebException HResult=0x80131509 Message=远程服务器返回错误: (…

算法随笔——wqs二分

学习链接 学习链接 应用条件选择恰好 \(x\) 个物品,求最优值 设 \(x\) 对应最优值 \(f_x\) ,\((x,f_x)\) 在图像上呈现为凸包。 无数量限制问题简单可做问题转化 有 \(n\) 个物品,恰好选 \(m\) 个,计算最优值。 做法例题 模版题:P2619

modbus设备数据 转 profinet IO项目案例

目录 1 案例说明 1 2 VFBOX网关工作原理 1 3 准备工作 2 4 设置网关采集MODBUS从站数据 2 5 用PROFINET IO协议转发数据 8 6 案例总结 10 1 案例说明设置网关采集Modbus设备数据 把采集的数据转成profinet IO协议转发给其他系统。2 VFBOX网关工作原理 VFBOX网关是协议转换网关,…

WPF开发 direct3d11 调试报错

环境:VS2022 WPF Win11 过程:准备调试d3d11着色器转换nv12->rgb的过程 报错信息:DXGI_ERROR_SDK_COMPONENT_MISSING 应用程序请求的操作依赖于已缺失或不匹配的 SDK 组件。 解决方案::需要在自己电脑中进行设置 【设置】-【系统】-【可选功能】-【查看功能】-【图形工具…

Cloudera安装指南:打造你的大数据基础环境

Cloudera manage系统环境准备、基础环境安装、集群部署以及应用组件安装等全方位的技术运维内容。无论您是初学者还是资深工程师,都能在这里找到适合自己的学习资料和实战经验。我们致力于为您提供最新、最全面的Cloudera大数据技术运维知识,帮助您轻松应对各种技术挑战。Clo…