资讯专栏INFORMATION COLUMN

使用Data URI Scheme优雅的实现前端导出csv

liujs / 2448人阅读

摘要:受限于请求需要后端分页接口性能等原因不得不放弃的导出方式。所以我需要寻找一种可行的合理的优雅的导出方案,那就是。方案实现方案介绍是利用标签的和属性来实现的。至此,这个问题算是完整的解决了。

问题描述

项目里需要实现一个导出csv的功能,这是个老生常谈的需求,而且我们使用的是iview的组件库,按道理说实现起来应该简单,但实则不然,我在做的时候遇到了一些问题。受限于请求需要token后端分页接口性能等原因不得不放弃iview的导出方式。所以我需要寻找一种可行的、合理的、优雅的导出方案,那就是Data URI Scheme

方案实现 方案介绍

Data URI Scheme是利用HTML标签的hrefsrc属性来实现的。他看起来像是这样的:


或者

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的实现

另外,在我写这篇文章的时候我发现iviewexport-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

相关文章

  • 文件下载那点事

    摘要:不过这种方式有问题,目前查到的大部分过程都是会在服务器新建出一个文件,等下载完毕在做删除,还没有找到可以跨过这一步的方式。 showImg(https://segmentfault.com/img/remote/1460000018850368); Content-Disposition / Content-Type Content-Disposition http 头部的 Conte...

    PascalXie 评论0 收藏0
  • javascript实现前端将数据导出excel两种方式

    javascript实现纯前端将数据导出excel是有两种方式,现在就为大家介绍:  方法一  将table标签,包括tr、td等对json数据进行拼接,直接在table的表格上体现出,但此方法的弊端在于输出的是伪excel,即使是生成xls为后缀的文件,可文件形式上还是html,  代码如下:  <html>   <head>   <pstyle="f...

    3403771864 评论0 收藏0
  • 关于个人开源项目(vue app)一些总结

    摘要:关于个人开源项目的一些总结项目地址项目简介此项目名叫。网站目前实现了登录注册日历导入文件考勤导出缺勤名单等核心功能。这对于小型项目来说并没有什么问题。编译后的大小关于文件上传与导出功能文件上传导出可以说是此项目最关键的点了。 关于个人开源项目(vue app)的一些总结 项目地址 https://github.com/BYChoo/record 项目简介 此项目名叫:Record。是以...

    since1986 评论0 收藏0
  • 关于个人开源项目(vue app)一些总结

    摘要:关于个人开源项目的一些总结项目地址项目简介此项目名叫。网站目前实现了登录注册日历导入文件考勤导出缺勤名单等核心功能。这对于小型项目来说并没有什么问题。编译后的大小关于文件上传与导出功能文件上传导出可以说是此项目最关键的点了。 关于个人开源项目(vue app)的一些总结 项目地址 https://github.com/BYChoo/record 项目简介 此项目名叫:Record。是以...

    QLQ 评论0 收藏0
  • 关于个人开源项目(vue app)一些总结

    摘要:关于个人开源项目的一些总结项目地址项目简介此项目名叫。网站目前实现了登录注册日历导入文件考勤导出缺勤名单等核心功能。这对于小型项目来说并没有什么问题。编译后的大小关于文件上传与导出功能文件上传导出可以说是此项目最关键的点了。 关于个人开源项目(vue app)的一些总结 项目地址 https://github.com/BYChoo/record 项目简介 此项目名叫:Record。是以...

    高胜山 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<