问题描述

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

方案实现

方案介绍

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

<img src="data:image/png;base64,iVBORw0KGgoAAA
ANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4
//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU
5ErkJggg==" alt="Red dot" />

或者

<a href="data:text/csv,something">download</a>

按照这种方案的介绍,我们把要导出的数据拼接在href指定位置就能实现导出的需求,代码实现看起来像这样:

<a href="" download="export.csv" id="export_csv" style="display='none'">download</a>
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;
}
  1. 变量声明部分源码链接
  2. 变量引用部分源码链接

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对象,所以我们要看看浏览的支持情况

恩,看起来没有问题,那我们来看看代码实现。

<a href="" download="export.csv" id="export_csv" style="display='none'">download</a>
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

使用Data URI Scheme优雅的实现前端导出csv相关推荐

  1. 编码 data:text/html;c,关于 Data URI Scheme -- data:image/jpg;base64

    转载一篇大神的文章 大家可能注意到了,网页上有些图片的src或css背景图片的url后面跟了一大串字符,比如: data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqA ...

  2. 服务器端发送邮件签名采用Data URI scheme包含图片

    要在服务器端基于HTML,拼接邮件内容,原来用户使用outlook采用了邮件签名,签名里含有公司Logo的图片,Outlook的msg文件里是专有的cid:xxxx,这里借用Data URI sche ...

  3. data URI scheme及其应用

    data URI scheme通俗来讲就是图片直接塞到HTML而不是由HTTP.这样从表面上看会降低一次HTTP的请求,实现了对于网页的优化(只是看了其它一些文章data URI由于将图片採用了bas ...

  4. Data URI scheme 在 html 中嵌入小图片

    例如: <img src="https://img-blog.csdnimg.cn/2022010704064257868.png" /> 这会显示一张图片,网上的资料 ...

  5. Data URL和图片,及Data URI的利弊

    Data URL给了我们一种很巧妙的将图片"嵌入"到HTML中的方法.跟传统的用img标记将服务器上的图片引用到页面中的方式不一样,在Data URL协议中,图片被转换成base6 ...

  6. Data URI详细介绍

    一.URI介绍 URI(统一资源标识符) 是 uniform resource identifier的缩写,它定义了接受内容的协议以及附带的相关内容,如果附带的相关内容是一个地址,那么此时的 URI ...

  7. 前端性能优化:使用Data URI代替图片SRC

    日期:2013-7-6  来源:GBin1.com 提升页面大小的效率,不仅仅是取决于使用精灵或是压缩代码,给定页面的请求数量在前端性能中也占有了很不小的重量.减少请求可以让你的网站加载更快,而其中一 ...

  8. 【Win10 UWP】URI Scheme(二):自定义协议的处理和适用场景

    上一篇提到Windows Store协议的使用,其实Windows Store协议仅是系统内建的一种协议规则.我们也可以自己定义一套规范的URI-Scheme,除了可以给其他App调用外,本应用也可以 ...

  9. 编码 data:text/html;c,[网页设计]图片base64编码利器:在线 Data URI 生成工具 – Duri.me...

    这篇文章介绍一款在线的图片 base64 编码利器 - Duri.me.data URI 图片是 base64编码的图片文件,可以嵌入到 HTML 或者 CSS 文件中,能够减少 HTTP 请求,提高 ...

最新文章

  1. Linux下“/”和“~”的区别
  2. 什么是图数据库?图数据库实践与创新浅析
  3. Android投票列表设计,AndroidCustomView一个简单的投票排名对比图
  4. xmlns=http://schemas.xmlsoap.org/wsdl/,这是什么意思,我只知道:xmlns:xx=....,
  5. 性感的CSS Menus
  6. LeetCode--055--跳跃游戏(java)
  7. 计算机组成原理设计性实验,《计算机组成原理》设计性实验报告.doc
  8. 益生菌拯救“社恐”?肿瘤攘外安内?胎盘似癌?这个世界怎么了。。。
  9. Android异常总结--- java.net.SocketTimeoutException: Transport endpoint is not connected
  10. 触发事件_SAP 通过事件触发后台JOB
  11. Flash必要的系统组件未能正常运行
  12. Pytest 自动化测试框架
  13. Python自定义模块
  14. java扫描条形码接口_javaweb条形码产生、打印、扫描
  15. 免费的IT类技术书籍大全
  16. 阿里测试左移和开发赋能分享
  17. Boost库安装与使用
  18. Perma.cc停止学术链接腐烂
  19. 关于线程的interrupt与sleep问题
  20. windows平台下静态库(.lib)和动态库(.dll)使用

热门文章

  1. 『C#基础』XML文件的读与写
  2. Linux时间不准确的问题![转]
  3. 通过实验来理解代理ARP(二)
  4. 转:c++builder读写INI文件
  5. 无限级分销系统数据库表设计
  6. swift扩展Extensions
  7. iOS11以后启动图尺寸
  8. UWP 保存用户设置
  9. 你是否理解js的Object与Function与原型链
  10. HTML5程序开发范例宝典(韩旭著)读书笔记之渐变背景