#傳統方法
利用iframe 或 form.submit 或 windows.open直接向后端發請求,后端返回文件流,后端處理成功后會直接返回到頁面,瀏覽器會整理並打開自己的保存下載文件機制 。
1、利用form.submit直接向后端提交,后端返回文件流
1)前端代碼:
1 var downloadURL = "RestHandle.ashx"; 2 var testForm = $("<form>"); //定義一個form表單 3 testForm.attr('style','display:none'); //設置form表單屬性 4 testForm.attr('target',''); 5 testForm.attr('method','post'); 6 testForm.attr('action',downloadURL); 7 8 var nameInput = $('<input>'); //構造formdata 9 nameInput.attr('type','hidden'); 10 nameInput.attr('name','fileName'); 11 nameInput.attr('value','test.txt'); 12 13 $('body').append(testForm); //將表單放置在web中 14 testForm.append(nameInput); //將formdata添加到表單上 15 testForm.submit(); //表單提交 16 testForm.remove(); //表單移除
2)服務端代碼,以asp.net為例:
1 public class TestHandler : IHttpHandler 2 { 3 4 public void ProcessRequest(HttpContext context) 5 { 6 string fileName = context.Request["FileName"];//客戶端傳送過來的要下載的文件名 7 string filePath = System.Web.HttpContext.Current.Server.MapPath("DownLoad/" + fileName);//路徑 8 9 FileInfo newFile = new FileInfo(filePath); 10 11 //以字符流的形式下載文件 12 FileStream fs = new FileStream(filePath, FileMode.Open); 13 byte[] bytes = new byte[(int)fs.Length]; 14 fs.Read(bytes, 0, bytes.Length); 15 fs.Close(); 16 context.Response.ContentType = "application/octet-stream"; 17 //通知瀏覽器下載文件而不是打開 18 context.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8)); 19 context.Response.BinaryWrite(bytes); 20 context.Response.Flush(); 21 context.Response.End(); 22 } 23 24 public bool IsReusable 25 { 26 get 27 { 28 return false; 29 } 30 } 31 }
3)優缺點:
優點 :兼容性良好,傳統方式,不會出現URL長度限制問題;
缺點:拿不到后端處理這個過程的時機,無法根據回調函數做交互以及進度提示
2、利於iframe直接向后端提交,后端返回文件流
1)前端代碼:
1 function downFileByIframe(parameters) { 2 var downloadURL = "TestHandler.ashx?FileName=test.txt"; 3 var iframe = document.createElement("iframe"); 4 iframe.src = downloadURL; 5 iframe.style.display = "none"; 6 document.body.appendChild(iframe); 7 }
2)后端代碼:同上
3)優缺點:
優點: 兼容性較好
缺點: *html中會增加多余的iframe元素,增加了維護成本;
*拿不到后端處理這個過程的時機,無法根據回調函數做交互以及進度提示;
*URL長度有限制;
3、使用windows.open下載文件
1)前端代碼
1 var downloadURL = "TestHandler.ashx?FileName=test.txt"; 2 window.open(downloadURL);
2)后端代碼:同上
3)優缺點:
優點: 兼容性良好,代碼簡潔;
缺點: *URL長度有限制;
*拿不到后端處理這個過程的時機,無法根據回調函數做交互以及進度提示;
4、解決“無法根據回調函數做交互”的問題:ajax提交,后端返回在線文件地址
利用ajax去提交請求,后端會返回一個線上的文件地址,前端可以通過原生的window.open打開這個地址就可以實現下載;
也可以通過a標簽設置href以及download屬性,並自動點擊實現其下載功能,關於其兼容性問題,可以判斷download屬性是否存在來彌補。
1)優缺點:
優點 :可以拿到其返回時機,可以做交互;
缺點 :線上產生大量的中間臨時文件,可以用設置時限來優化。解決方案:可使用大廠的雲存儲,從而減少臨時文件的產生;
2)前端代碼:
1 $.ajax({ 2 type: "post", 3 url: "TestHandler.ashx", 4 data: {'FileName':'test.txt'}, 5 success: function (res) { 6 if (res.Status) { 7 // window.open或者a標簽下載 8 var isSupportDownload = 'download' in document.createElement('a'); 9 if (isSupportDownload) { 10 var $a = $("<a>"); 11 $a.attr({ 12 href: res.url, 13 download: 'filename' 14 }).hide().appendTo($("body"))[0].click(); 15 } else { 16 window.open(res.url) 17 } 18 } else { 19 alert(res.Message); 20 } 21 } 22 })
5、解決“無法根據回調函數做交互”的問題:jquery-download 插件
jquery.download.js插件github地址:https://github.com/johnculviner/jquery.fileDownload/blob/master/src/Scripts/jquery.fileDownload.js
jquery.download.js插件cdn地址:https://www.bootcdn.cn/jquery.fileDownload/
支持場景 : 與上面的幾種方案相比,這個模塊提供的方案更加完善,而不是局限於某種方案,相當於將上面的幾種方案結合了起來, 使用率很高。在源碼中,我們可以看到在這個模塊中針對各個瀏覽器和相應的屬性是否支持進行了比較全面的兼容。其對應的下載文件方案包括了以下幾種。
- window.open(url)打開某個文件地址
- iframe的框架中,設置src屬性,通過iframe進行文件的下載,支持文件地址
- 通過form標簽,設置action的文件地址,然后通過form的提交來完成文件的下載
1)前端代碼:
1 var downloadURL = "TestHandler.ashx"; 2 $.fileDownload(downloadURL, { 3 httpMethod: 'post', 4 data: { 'FileName': 'test.txt' }, 5 prepareCallback: function (url) { 6 console.log("文件下載中..."); 7 // 數據加載動畫 8 $("body").append('<div id="Loading" style="background:url(images/load.png) top center no-repeat;"></div>'); 9 }, 10 abortCallback: function (url) { 11 // 異常終止 12 console.log("文件下載異常!!"); 13 $("#Loading").remove(); 14 }, 15 successCallback: function (url) { 16 console.log("文件下載成功!!"); 17 $("#Loading").remove(); 18 }, 19 failCallback: function (html, url) { 20 console.log("文件下載失敗!!"); 21 $("#Loading").remove(); 22 } 23 });
2)后端代碼:
1 public void ProcessRequest(HttpContext context) 2 { 3 string fileName = context.Request["FileName"];//客戶端保存的文件名 4 string filePath = System.Web.HttpContext.Current.Server.MapPath("DownLoad/" + fileName);//路徑 5 6 FileInfo newFile = new FileInfo(filePath); 7 8 //以字符流的形式下載文件 9 FileStream fs = new FileStream(filePath, FileMode.Open); 10 byte[] bytes = new byte[(int)fs.Length]; 11 fs.Read(bytes, 0, bytes.Length); 12 fs.Close(); 13 14 context.Response.ContentType = "application/octet-stream"; 15 context.Response.AddHeader("Content-Disposition", "attachment; filename=" + HttpUtility.UrlEncode(fileName, System.Text.Encoding.UTF8)); 16 context.Response.BinaryWrite(bytes); 17 18 //該cookie用於告訴jquery.fileDownload.js文件下載成功 19 context.Response.Cookies.Add(new HttpCookie("fileDownload", "true")); 20 context.Response.Flush(); 21 context.Response.End(); 22 }
注意: 這里的后端代碼增加了一個名為“fileDownload”的cookie的返回;jquery.download.js插件使用該cookie來判斷是否下載成功,從而進入成功回調函數(successCallback);
#新興方案
1、利用Html5的download屬性進行下載
1)前端代碼
1 <a href="TestHandler.ashx?FileName=test.txt" download="test1.txt">DownloadAttrTest</a>
2)后端代碼:同上
3)優缺點:
優點:代碼簡潔
缺點:存在瀏覽器兼容性的問題
4)參考:
https://www.zhangxinxu.com/wordpress/2016/04/know-about-html-download-attribute/
2、利用Html5的Blob對象實現對文件流進行下載
(1)、 使用原生js發送ajax實現
1)前端代碼:
1 function downByBlob_1(parameters) { 2 var downloadURL = "TestHandler.ashx?FileName=zip.rar"; 3 let xhr = new XMLHttpRequest() 4 let fileName = 'zip.rar' // 文件名稱 5 xhr.open('GET', downloadURL, true); 6 xhr.responseType = 'arraybuffer'; 7 //xhr.setRequestHeader('xx', 'xxxxx') // 請求頭中添加信息 8 xhr.onload = function () { 9 if (this.status === 200) { 10 let type = xhr.getResponseHeader('Content-Type') 11 12 let blob = new Blob([this.response], { type: type }) 13 if (typeof window.navigator.msSaveBlob !== 'undefined') { 14 /* 15 * IE workaround for "HTML7007: One or more blob URLs were revoked by closing 16 * the blob for which they were created. These URLs will no longer resolve as 17 * the data backing the URL has been freed." 18 */ 19 window.navigator.msSaveBlob(blob, fileName); 20 } else { 21 let URL = window.URL || window.webkitURL; 22 let objectUrl = URL.createObjectURL(blob); 23 console.log(objectUrl); 24 //"blob:http://localhost:10614/3e48b856-fca6-4e4c-b780-1c4a7066f42e" 25 if (fileName) { 26 var a = document.createElement('a'); 27 // safari doesn't support this yet 28 if (typeof a.download === 'undefined') { 29 window.location = objectUrl 30 } else { 31 a.href = objectUrl; 32 a.download = fileName; 33 document.body.appendChild(a); 34 a.click(); 35 a.remove(); 36 } 37 } else { 38 window.location = objectUrl; 39 } 40 } 41 } 42 } 43 xhr.send(); 44 }
2)后端代碼:同上
(2)、 使用結合jq發送ajax請求實現,需要引入jquery.binarytransport.js插件,其擴展了jq的ajax的dataType的設置;
jquery.binarytransport.js插件github地址:https://github.com/henrya/js-jquery/tree/master/BinaryTransport
注意:當下載的是純文本文件時,是不需要引入插件,ajax也不用配置dataType,直接用jq的ajax即可;
1)前端代碼:
1 function downByBlob_2(parameters) { 2 $.ajax({ 3 type: "post", 4 url: "TestHandler.ashx", 5 data: { 'FileName': 'zip.rar' }, 6 dataType: 'binary', 7 responseType: 'arraybuffer', 8 success: function (msg) { 9 let blob = new Blob([msg]); 10 11 console.log("Blob:" + msg); //msg 已不是亂碼 12 let url = window.URL.createObjectURL(blob); 13 14 let a = document.createElement("a"); 15 document.body.appendChild(a); 16 a.href = url; 17 a.download = 'zip.rar'; //命名下載名稱 18 a.click(); //點擊觸發下載 19 window.URL.revokeObjectURL(url); //下載完成進行釋放 20 } 21 }); 22 }
2)后端代碼:同上
3)參考:
http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/
https://blog.csdn.net/aydongzhiping/article/details/82462473
3、新興方案中的綜合方案:file-saver
(1)、FileSaver.js 功能特點
- FileSaver.js 是一款基於 HTML5 完成文件保存的插件,它可以幫我們直接從網頁中導出多種格式文件。
- 同時對於那些本身不支持 HTML5 W3C saveAs() FileSaver 接口的瀏覽器,FileSaver.js 也提供了支持。
- 使用 FileSaver.js 可以讓 Web 應用完美的生成文件,或者保存那些不應該發送到外部服務器的敏感信息。是一種簡單易用的瀏覽器端文件保存方案。
(2)、安裝
FileSaver.js github地址:https://github.com/eligrey/FileSaver.js
可直接下載 FileSaver.js 然后在頁面中引用;
npm、bower 安裝:
npm install file-saver --save bower install file-saver
(3)、demo:使用 FileSaver.js下載后端返回的文件流;
1)前端代碼:
1 function downByFileSaver(parameters) { 2 saveAs('TestHandler.ashx?FileName=zip.rar'); 3 }
2)后端代碼:同上
4、新興方案的優缺點:
優點:技術新穎,某些場景下使用方便;
缺點:兼容性不好;
#參考
https://juejin.im/post/5bd5547a6fb9a05cdd2d5109
https://juejin.im/post/5bd1b0aa6fb9a05d2c43f004
https://www.cnblogs.com/yunser/p/7629399.html
https://blog.csdn.net/wt346326775/article/details/83617663
————————————————————————————————————————————————————