前端學習隨記の下載上傳篇 —— 下載篇

前端學習隨記の下載上傳篇 —— 下載篇

閑言: 懶懶懶?。?!好長時間不寫文章了,一直出差魔都,學習一些其他知識開發(fā)項目,也時不時的空閑時間深度學習一些前端基礎知識。好吧,不找理由,就是懶哇哈哈(????)。

demo代碼:https://github.com/NARUTOne/DownAndUp.git

參考傳送門:
http://www.cnblogs.com/voiphudong/p/3284724.html
https://scarletsky.github.io/2016/07/03/download-file-using-javascript/#參考資料
https://developer.mozilla.org/zh-CN/docs/Web/API/FileSystem

引言###

上傳下載一直是項目上非常常見的需求,也是對于我這種前端小白來說一直隱隱犯怵的地方,不太熟悉,加上項目上用過一次,同事朋友也問過遇到過,所以打算好好惡補這塊↖(ω)↗。本篇先說下下載,上傳留著下篇來說,歡迎關注留bug.

幾種下載方式

前后端下載方式原理簡述:

1)標準URL下載方式:?可以通過在web頁面中嵌入 url超級鏈接,標準的HTTP GET請求。對于服務器端web根目錄有一個test.zip的文件。此種方法的弊端是完全暴露了文件test.zip的網(wǎng)站路徑,而且動態(tài)性不夠靈活。

2)通過服務器端腳本向瀏覽器方(stdout)輸出二進制流的方式下載:?上述方法可以在服務器端 通過 腳本程序 download.php ,并且根據(jù)傳入的查詢字符串f=test.zip定位服務器上文件系統(tǒng)test.zip的路徑,然后按二進制流的方式發(fā)送給客戶端瀏覽器,那么客戶端瀏覽器就會彈出一個“下載對話框”了。

form 表單下載

POST的URL下載鏈接,可以通過設置form表單的action 以及 表單元素值來完成下載。

function downLoad () {
  var form = document.createElement('form');   //定義一個form表單
  form.style = 'display:none';   //下面為在form表單中添加查詢參數(shù)
  form.target = '';
  form.method = 'post';
  form.action = url;//下載接口

  var input1 = document.createElement('input');
  input1.type = 'hidden';
  Input1.name = 'exportData';
  input1.value = (new Date()).getMilliseconds(); 

  document.body.appendChild(form)  //將表單放置在web中
  form.appendChild(input1);   //將查詢參數(shù)控件提交到表單上
  form.submit();   //表單提交
}

iframe

iframe有一個src屬性,其本質就是發(fā)送http請求,GET一個頁面或者數(shù)據(jù),可以通過一個動態(tài)生成的隱藏的iframe來得到下載的二進制文件。

function download(){
  var IFrameRequest=document.createElement("iframe");
  IFrameRequest.id="IFrameRequest";
  IFrameRequest.src="/test.zip";
  IFrameRequest.style.display="none";
  document.body.appendChild(IFrameRequest);
}

HTML5のdownload屬性

由于瀏覽器的安全策略的限制,我們通常只能通過一個額外的頁面,訪問某個文件的 url 來實現(xiàn)下載功能,但是這種用戶體驗非常不好。HTML 5 里面為 a 標簽添加了一個 download 的屬性,我們可以輕易的利用它來實現(xiàn)下載功能。

<a href="http://somehost/somefile.zip" download="filename.zip">Download file</a>

a標簽添加 download 屬性,我們點擊這個鏈接的時候就會自動下載文件了~
順便說下,download 的屬性值是可選的,它用來指定下載文件的文件名。像上面的例子中,我們下載到本地的文件名就會是 filename.zip 拉,如果不指定的話,它就會是 somefile.zip 這個名字啦!

當然,我們還可以動態(tài)創(chuàng)建a標簽實現(xiàn)下載:

function download() {
  var a = document.createElement('a');
  var url = window.URL.createObjectURL(blob);
  var filename = 'what-you-want.txt';
  a.href = url;
  a.download = filename;
  a.click();
  window.URL.revokeObjectURL(url);
}

window.URL 里面有兩個方法:
createObjectURL 用 blob 對象來創(chuàng)建一個 object URL(它是一個 DOMString),我們可以用這個 object URL 來表示某個 blob 對象,這個 object URL 可以用在 href 和 src 之類的屬性上。
revokeObjectURL 釋放由 createObjectURL 創(chuàng)建的 object URL,當該 object URL 不需要的時候,我們要主動調用這個方法來獲取最佳性能和內存使用。
當然,如果你沒有blob對象的url,也可以不用window.URL,直接使用下載地址url。

HTML5のFileSystem

由于這種方法目前大多數(shù)瀏覽器不支持,僅僅chrome支持,具體方式可以查看大神們的文章,我就不搬運了。(????)
https://imququ.com/post/a-downloader-with-filesystem-api.html

其他方式

Window.open(url):這種方式在目前的網(wǎng)絡環(huán)境及安全限制下被攔截已經(jīng)不太好使了,主要用來是打開新窗口下載。

var new_window = null;
function downLoad () {
  var isSure=confirm("是否下載")
  if (isSure){
    new_window = window.open()
    new_window.location.;
    document.getElementById('result').innerHTML = "You downLoad OK!"
  }
  else{
    document.getElementById('result').innerHTML = "You pressed Cancel!"
  }
}
function closeDownLoad() {
  new_window  && new_window.close();
}

//使用a鏈接target='_blank',則不會攔截下載
function AdownLoad() {
  var url = 'https://github.com/WZOnePiece/study-draggable/archive/master.zip';
  var a = document.createElement("a");
  a.setAttribute("href", url);
  a.setAttribute("target", "_blank");
  a.setAttribute("id", "camnpr");
  document.body.appendChild(a);
  a.click();
}

這里主要是用window.open 打開窗口,接著使用location.href = url進行重定向避免攔截進行下載。

補充知識

Blob 對象

Blob 全稱是 Binary large object,它表示一個類文件對象,可以用它來表示一個文件。根據(jù) MDN 上面的說法,F(xiàn)ile API 也是基于 blob 來實現(xiàn)的。

構建 blob 的方式就是通過服務器返回的文件來創(chuàng)建 blob ,采用File API及Fetch API。

fetch('http://somehost/somefile.zip').then(res => res.blob().then(blob => {
  var a = document.createElement('a');
  var url = window.URL.createObjectURL(blob);
  var filename = 'myfile.zip';
  a.href = url;
  a.download = filename;
  a.click();
  window.URL.revokeObjectURL(url);
}))

注意:Fetch API 目前瀏覽器支持不好,詳情看https://developer.mozilla.org/zh-CN/docs/Web/API/Fetch_API/Using_Fetch
File API的詳細介紹:https://developer.mozilla.org/zh-CN/docs/Using_files_from_web_applications
可以利用fetch配合reader對象來實現(xiàn)進度條功能

限制

1、不同瀏覽器對 blob 對象有不同的限制

Supported browsers

Browser Constructs as Filenames Max Blob Size Dependencies
Firefox 20+ Blob Yes 800 MiB None
Firefox < 20 data: URI No n/a Blob.js
Chrome Blob Yes [500 MiB][3] None
Chrome for Android Blob Yes [500 MiB][3] None
Edge Blob Yes ? None
IE 10+ Blob Yes 600 MiB None
Opera 15+ Blob Yes 500 MiB None
Opera < 15 data: URI No n/a Blob.js
Safari 6.1+* Blob No ? None
Safari < 6 data: URI No n/a Blob.js

2、構建完 blob 對象后才會轉換成文件。

文件大點的話,要等到下載完文件之后才能構建 blob 對象,再轉化成文件,頁面顯示上不太友好,沒有提示。這時建議采用a標簽,防止用戶的錯誤認知造成重復點擊下載,資源浪費。

服務器出錯

  • 1、window.open(url)

打開一個帶錯誤信息的頁面

  • 2、window.location.href

頁面將跳轉到一個錯誤頁面

  • 3、iframe

用戶感知不到任何變化

  • 4、a標簽

直接出現(xiàn) 下載失敗

當然,如果response header里有content-disposition字段的話,瀏覽器都會下載一個帶錯誤信息的文件。這時候,其實我們可以多發(fā)一個ajax/fetch請求,先檢測下接口狀態(tài),然后再取做下載邏輯。但這樣就對服務器造成了額外的開銷。

這樣的體驗都不太好,作為一個追求極致體驗的程序猿,我們應該重新思考下,如何提升用戶體驗。

結語##

O(∩_∩)O,這篇下載篇就這樣簡單介紹下,至于還有其他的方式,歡迎留言告知;代碼及描述上有bug也希望不吝指出。謝謝哈!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
【社區(qū)內容提示】社區(qū)部分內容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內容

  • 閑言: 上篇我們學習了一些下載的js前端方式,這篇來講講上傳篇。這也是在項目需求中很常見的O(∩_∩)O。 dem...
    迷緣火葉閱讀 613評論 0 1
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,506評論 19 139
  • 第一次做內購,審核失敗。。。ios內購 元數(shù)據(jù)丟失 審核信息里的審核屏幕快照跟備注要填寫,不然就失敗的。第一次用I...
    工匠良辰閱讀 11,766評論 5 2
  • 02 “二位,睡得可好?” 一股飛速旋轉的黑煙席卷而來。少年,老者,還有仆人,三人居高臨下地現(xiàn)身于我們面前。 “明...
    井水花生閱讀 1,035評論 5 9
  • 迭代器是一個對象,用于將容器對象作為列表遍歷。在 JavaScript 中,迭代器對象不是一個獨立的內置對象,而是...
    趙然228閱讀 396評論 0 1

友情鏈接更多精彩內容