摘要:受限于请求需要后端分页接口性能等原因不得不放弃的导出方式。所以我需要寻找一种可行的合理的优雅的导出方案,那就是。方案实现方案介绍是利用标签的和属性来实现的。至此,这个问题算是完整的解决了。
问题描述
项目里需要实现一个导出csv的功能,这是个老生常谈的需求,而且我们使用的是iview的组件库,按道理说实现起来应该简单,但实则不然,我在做的时候遇到了一些问题。受限于请求需要token、后端分页、接口、性能等原因不得不放弃iview的导出方式。所以我需要寻找一种可行的、合理的、优雅的导出方案,那就是Data URI Scheme。
方案实现 方案介绍Data URI Scheme是利用HTML标签的href和src属性来实现的。他看起来像是这样的:
或者
download
按照这种方案的介绍,我们把要导出的数据拼接在href指定位置就能实现导出的需求,代码实现看起来像这样:
download
function export_csv (data) { $("#export_csv").href = "data:attachment/csv," + encodeURI(data); $("#export_csv").click(); setTimeout(function () { $("#export_csv").href = ""; }) } export_csv(csv_data_str);
测试发现,妥妥的,没毛病。
存在问题在实践中这个方案是有限制的、不安全的:在chrome的实现中Data URI Scheme允许的URL的最大限制为2MB(其他浏览器这里不做讨论)。
一开始并不知道是超过2MB才会出问题,只是发现:
当在下载的文件比较大(超过2.7MB)的时候Chrome会报这样的错误:
下载 失败-网络错误
后来google到这个限制是2MB,因为没有官方文档说明,感觉2MB的说法不是很确定,所以去扒了Chromium源码,找到了相关代码:
const size_t kMaxURLChars = 2 * 1024 * 1024; ... if (!iter->ReadString(&s) || s.length() > url::kMaxURLChars) { *p = GURL(); return false; }
变量声明部分源码链接
变量引用部分源码链接
2MB的限制算是实锤了,同时发现2010年就有人在Chromium论坛提出2MB太小了了,但是一直讨论到2019年也没有明显的改善(只是改了图片部分)。唉,chromium不改,我们能怎么办呢?
方案改进chromium不改,那我们只能自己想办法了,于是有大牛提出来使用URL.createObjectURL + Blob来突破这个限制。
借助Blob对象和URL.createObjectURL我们可以得到一个很短的、而且几乎与内容长度无关的URL:
blob:https://xxx.com/0bde569d-20a2-4085-95e6-dcec242962c6
这样就能突破Chrome对Data URI Scheme URL大小的限制了。
当然呢,我没用过URL.createObjectURL这个方法,也没用过Blob对象,所以我们要看看浏览的支持情况
恩,看起来没有问题,那我们来看看代码实现。
download
function export_csv (data) { const BOM = "uFEFF"; let blob_obj = new Blob([BOM + data], {type: "text/csv"}); let download_url = URL.createObjectURL(blob_obj); $("#export_csv").href = download_url; $("#export_csv").click(); setTimeout(function () { // 通过createObjectURL创建的url需要通过revokeObjectURL()来释放 URL.revokeObjectURL(download_url); $("#export_csv").href = ""; }) } export_csv(csv_data_str);
如此,问题解决了,这样就不怕超过2MB的CSV的导出了。
但是Chrome对Blob对象的大小有限制吗?
Good question !
我在chromium Blob的说明文档中找到一个表:
Device | Ram | In-Memory Limit | Disk | Disk Limit | Min Disk Availability |
---|---|---|---|---|---|
Cast | 512 MB | 102 MB | 0 | 0 | 0 |
Android Minimal | 512 MB | 5 MB | 8 GB | 491 MB | 10 MB |
Android Fat | 2 GB | 20 MB | 32 GB | 1.9 GB | 40 MB |
CrOS | 2 GB | 409 MB | 8 GB | 4 GB | 0.8 GB |
Desktop 32 | 3 GB | 614 MB | 500 GB | 50 GB | 1.2 GB |
Desktop 64 | 4 GB | 2 GB | 500 GB | 50 GB | 4 GB |
从这个表中,大概可以看出来在In-Memory Storage的时候桌面版64位Chrome Blob的上限为2GB(在Chrome 57上限是500MB)。所以现在看来这种方法应该是安全的。至此,这个问题算是完整的解决了。
iview的实现另外,在我写这篇文章的时候我发现iview的export-csv方法也是按照这个方案实施的,而且做了更多兼容,可以方便大家参考。但他在资源释放的地方做的还需改进,也希望大家注意。
参考文档Data protocol URL size limitations
Excellent Export and the Chrome URL limit
Data_URI_scheme
excellentexport pull request
无法在nodejs中下载大文件
Issue 69227: Loading large URLs kills the renderer
Issue 375297: the total blobs" size cannot exceed about 500MiB
Is there any limitation on JavaScript Max Blob size
chromium/url/url_param_traits.cc#L36
chromium/url/url_constants.cc#L32
iview 3.x export-csv
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/101752.html
javascript实现纯前端将数据导出excel是有两种方式,现在就为大家介绍: 方法一 将table标签,包括tr、td等对json数据进行拼接,直接在table的表格上体现出,但此方法的弊端在于输出的是伪excel,即使是生成xls为后缀的文件,可文件形式上还是html, 代码如下: <html> <head> <pstyle="f...
摘要:关于个人开源项目的一些总结项目地址项目简介此项目名叫。网站目前实现了登录注册日历导入文件考勤导出缺勤名单等核心功能。这对于小型项目来说并没有什么问题。编译后的大小关于文件上传与导出功能文件上传导出可以说是此项目最关键的点了。 关于个人开源项目(vue app)的一些总结 项目地址 https://github.com/BYChoo/record 项目简介 此项目名叫:Record。是以...
摘要:关于个人开源项目的一些总结项目地址项目简介此项目名叫。网站目前实现了登录注册日历导入文件考勤导出缺勤名单等核心功能。这对于小型项目来说并没有什么问题。编译后的大小关于文件上传与导出功能文件上传导出可以说是此项目最关键的点了。 关于个人开源项目(vue app)的一些总结 项目地址 https://github.com/BYChoo/record 项目简介 此项目名叫:Record。是以...
阅读 1260·2021-11-23 09:51
阅读 1627·2021-11-16 11:45
阅读 4013·2021-10-09 09:43
阅读 2681·2021-07-22 16:47
阅读 944·2019-08-27 10:55
阅读 3449·2019-08-26 17:40
阅读 3083·2019-08-26 11:39
阅读 3228·2019-08-23 18:39