问题描述项目里需要实现一个导出csv的功能,这是个老生常谈的需求,而且我们使用的是iview的组件库,按道理说实现起来应该简单,但实则不然,我在做的时候遇到了一些问题。受限于请求需要token、后端分页、接口、性能等原因不得不放弃iview的导出方式。所以我需要寻找一种可行的、合理的、优雅的导出方案,那就是Data URI Scheme。方案实现方案介绍Data URI Scheme是利用HTML标签的href和src属性来实现的。他看起来像是这样的:<img src=“data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==” 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的实现中这个url最大限制为2MB。所以,当在Chrome下载的文件大小超过2MB chrome便会报这样的错误(其他浏览器这里不做讨论):下载失败-网络错误这里2MB的大小可以在chromium源码中可以看到:const size_t kMaxURLChars = 2 * 1024 * 1024;…if (!iter->ReadString(&s) || s.length() > url::kMaxURLChars) { *p = GURL(); return false;}变量声明部分源码链接变量引用部分源码链接而关于2MB限制的问题在chromium论坛在2010年就被人作为bug提出来了,但是从2010年一直讨论到2019年也没有明显的改善。方案改进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的导出了,但是Blob对象有大小限制吗?Good question !我们在chromium的说明文档中可以看到一个表:DeviceRamIn-Memory LimitDiskDisk LimitMin Disk AvailabilityCast512 MB102 MB000Android Minimal512 MB5 MB8 GB491 MB10 MBAndroid Fat2 GB20 MB32 GB1.9 GB40 MBCrOS2 GB409 MB8 GB4 GB0.8 GBDesktop 323 GB614 MB500 GB50 GB1.2 GBDesktop 644 GB2 GB500 GB50 GB4 GB从这个表中,大概可以看出来在In-Memory Storage的时候桌面版64位Chrome Blob的上限为2GB(在Chrome 57似乎上限是500MB)。所以从现在看来这种方法应该是安全的。至此,这个问题算是完整的解决了。iview的实现另外,在我写这篇文章的时候我发现iview的export-csv方法也是按照这个方案实施的,而且做了更多兼容,可以方便大家参考。但他在资源释放的地方做的还需改进,也希望大家注意。参考文档Data protocol URL size limitationsExcellent Export and the Chrome URL limitData_URI_schemeexcellentexport pull request无法在nodejs中下载大文件Issue 69227: Loading large URLs kills the rendererIssue 375297: the total blobs’ size cannot exceed about 500MiBIs there any limitation on JavaScript Max Blob sizechromium/url/url_param_traits.cc#L36chromium/url/url_constants.cc#L32iview 3.x export-csv