摘要:受限于請求需要后端分頁接口性能等原因不得不放棄的導出方式。所以我需要尋找一種可行的合理的優雅的導出方案,那就是。方案實現方案介紹是利用標簽的和屬性來實現的。至此,這個問題算是完整的解決了。
問題描述
項目里需要實現一個導出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
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/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。是以...
閱讀 1274·2021-11-23 09:51
閱讀 1635·2021-11-16 11:45
閱讀 4060·2021-10-09 09:43
閱讀 2694·2021-07-22 16:47
閱讀 953·2019-08-27 10:55
閱讀 3456·2019-08-26 17:40
閱讀 3098·2019-08-26 11:39
閱讀 3238·2019-08-23 18:39