摘要:不過這種方式有問題,目前查到的大部分過程都是會在服務器新建出一個文件,等下載完畢在做刪除,還沒有找到可以跨過這一步的方式。
Content-Disposition / Content-Type Content-Disposition
http 頭部的 Content-Disposition字段,規定了返回的內容用什么形式展示
value | 含義 | 是否默認 |
---|---|---|
inline | 以網頁或者頁面的一部分 | 是 |
attachment | 以附件的形式下載并保存到本地 | 否 |
http.createServer((req, res) => { res.setHeader("Content-Disposition", "attachment") res.end("123 - 321 - 1234567") })
前端需要使用window.open 形式訪問 此路由就可以實現文件的下載
window.open(xxxx)
或者使用 H5新屬性 a 標簽
點擊下載Content-Type
http.createServer((req, res) => { res.setHeader("Content-Type", "application/octet-stream") res.end("123 - 321 - 1234567") })
同上前端使用 open 或者 a標簽進行處理
備注: 如果使用普通的請求,是不可以的,比如使用ajax
window.openwindow.open 可以下載文件的原因是,瀏覽器遇到無法解析的文件就是執行下載
當使用瀏覽器打開文件時, 如果它無法解析,那么就會把該文件下載下來
http.createServer((req, res) => { const data = fs.readFileSync("./Zip.zip") res.end(data) })
拿到的data是一個buffer 對象,那么直接寫一個Buffer可以實現下載么
data = new Buffer("我是誰,誰是我")
嘗試后發現,koa是可以的。但是原生直接這么寫是不行的
http.createServer((req, res) => { const newBuf = new Buffer("我是誰,誰是我") res.end(newBuf) })通過接口拿到數據之后進行下載
在實際項目中,文件下載可能出現的場景
對于已經在服務器存在的文件進行下載,比如圖片資源
將一些查詢數據導出到本地, 比如mysql查詢結果導出csv
對于已存在的資源,可以直接使用 上面說的 winodw.open 或者 a 標簽進行下載,那么對于不是以文件形式存在的資源呢
data URI經常見到使用 data URI scheme 的是圖片, 一般為了減少http請求,會將圖片直接以base64的形式展示在html中
也可以應用到文件下載中
router.get("/download", async (ctx, next) => { const newBUf = new Buffer("我是誰,誰是我") ctx.body = newBUf }
axios.get(`${path}`) .then(function ({data}) { let a = document.createElement("a"); a.href = "data:text/plain;charset=utf-8," + data; a.download = "myfilename.png"; a.click(); // 記得處理臨時元素 防止內存泄漏 a = null })Blob
Blob 是表示一個類文件對象,可以用它來表示一個文件
server 部分
http.createServer((req, res) => { res.setHeader("Access-Control-Allow-Origin", "*"); let end = "" if (req.url.includes("/down")) { const newBUf = new Buffer("我是誰,誰是我") end = newBUf } res.end(end) }
前端
const xhr = new XMLHttpRequest(); xhr.open("GET", path); xhr.responseType = "blob"; xhr.onload = function () { const blob = xhr.response; const url = URL.createObjectURL(blob); // 通過a標簽去下載 const link = document.createElement("a"); link.href = url; link.download = fileName; link.click(); link = null URL.revokeObjectURL(url); }; xhr.send();
嘗試用 window.open 方式,發現不可以
目前常用的各個第三方庫也支持返回內容為blob格式
axios.get(`${path}`, { responseType: "blob" })
或者 fetch
fetch(path).then(res => res.blob().then(blob =>{ ... })window.URL
createObjectURL
用 blob 對象來創建一個 object URL(它是一個 DOMString),我們可以用這個 object URL 來表示某個 blob 對象,這個 object URL 可以用在 a 標簽的 href屬性上,然后觸發點擊事件,就可以下載文件了
revokeObjectURL
為了避免避免內存泄漏,需要手動釋放創建的 object URL
缺點構建完 blob 對象后才會轉換成文件
從代碼就能看出,需要先將返回內容轉為blob才進行下載操作,如果用戶操作的是一個很大的資源,在等待文件正式下載前,還需要一段時間等待格式的轉化
實例 將mysql數據 導出 csv這邊直接用數據模擬mysql查詢結果, 在網上查到兩種拼接方式,肯定有其余的方案
第一種
const result = [ ["id", "oreder", "name", "status" ], [1, "201904120201", "正在加載", "已完成"], [18, "201904120204", "測試189", "待付款"], [22, "201904120209", "藍田日暖", "待付款"], ] // 可以看到 result 數組的第一組是 csv的各個字段標題 const data = csvData.reduce((cur, next) => `${cur + next.join(",")} `, "") const blob = new Blob([data]); const url = URL.createObjectURL(blob); let a = document.createElement("a"); a.href = url; a.download = filename; a.click(); a = null window.URL.revokeObjectURL(url);
第二種
const result = [ [1, "201904120201", "正在加載", "已完成"], [18, "201904120204", "測試189", "待付款"], [22, "201904120209", "藍田日暖", "待付款"], ] // result 就是正常的數據格式 // 解決亂碼問題 let dataType = "uFEFF" // 添加表格的頭子段 dataType += ([" 訂單編號", "用戶", "動態ID"].join(",")) dataType += " " csvData.forEach(item => { dataType += ([item.id, item.order, item.name, item.staus].join(",")) dataType += " " }) const blob = new Blob([dataType], {type: "text/csv"})如果有幾段流文件,前端需要下載拼接成一個完整文件,如何實現
肯定是在 server端進行文件的拼接操作,然后返回到前端下載
大致過程
const content1 = "這里是第1段文件內容" const content2 = "這里是第2段文件內容" ctx.body = { code:200, data: content1 + content2 }
前端就是上文中的blob 下載方式了
批量下載如何處理其實這個問題是在查詢資料的過程有人提到的問題
window.open
批量寫了多個 window.open 在Chrome中 可以正常使用,但是在safari中,只能打開一個窗口,下載一個文件
轉為下載一個zip 文件
感覺如果將所有文件合并成為一個xxx.zip 然后對 這個zip文件做下載。不過這種方式有問題,目前查到的大部分過程都是會在服務器新建出一個 zip 文件,等下載完畢在做刪除,還沒有找到可以跨過這一步的方式。
參考文章Data URI Scheme
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/103491.html
摘要:解決方法如果使用頁面數據不超過一屏禁止滾動,那么即使變成了頁面也不會有什么變化。 作者:@micky思 @wupq @yewq 在H5的開發中,個人的制作頁面布局習性不同,多多少少會產生在真機上input的光標和鍵盤的彈出會出現的各種BUG,文中整理了部分遇到的問題,歡迎新增 ios移動端輸入框上浮導致輸入位置偏移 問題原因:遮罩層定位為fixed,當鍵盤彈起時,ios11以及以下...
摘要:解決方法如果使用頁面數據不超過一屏禁止滾動,那么即使變成了頁面也不會有什么變化。 作者:@micky思 @wupq @yewq 在H5的開發中,個人的制作頁面布局習性不同,多多少少會產生在真機上input的光標和鍵盤的彈出會出現的各種BUG,文中整理了部分遇到的問題,歡迎新增 ios移動端輸入框上浮導致輸入位置偏移 問題原因:遮罩層定位為fixed,當鍵盤彈起時,ios11以及以下...
摘要:解決方法如果使用頁面數據不超過一屏禁止滾動,那么即使變成了頁面也不會有什么變化。 作者:@micky思 @wupq @yewq 在H5的開發中,個人的制作頁面布局習性不同,多多少少會產生在真機上input的光標和鍵盤的彈出會出現的各種BUG,文中整理了部分遇到的問題,歡迎新增 ios移動端輸入框上浮導致輸入位置偏移 問題原因:遮罩層定位為fixed,當鍵盤彈起時,ios11以及以下...
摘要:函數防抖場景假設網站有個搜索框用戶輸入文本我們會自動聯想匹配出一些結果供用戶選擇我們可能首先想到的做法就是監聽事件然后異步查詢結果但是如果用戶快速的輸入了一串字符假設是個字符那么就會在瞬間觸發次請求這無疑不是我們想要的我們想要的是用戶停止輸 函數防抖 場景 假設網站有個搜索框, 用戶輸入文本我們會自動聯想匹配出一些結果供用戶選擇,我們可能首先想到的做法就是監聽keypress事件, 然...
摘要:一直使用定義變量,的出現給變量定義增加了兩個大將,。聲明的變量,塊作用域,不重復聲明覆蓋,限制了變量的作用域,保證變量不會去污染全局變量,所以盡量將改為用。 一直使用var定義變量,ES6的出現給變量定義增加了兩個大將let,const。那它們有什么區別呢。 1、const關鍵字它的作用就是定義一個常量,一旦定義無法更改,不能重復聲明覆蓋; showImg(https://segmen...
閱讀 2924·2021-11-17 09:33
閱讀 1645·2021-10-12 10:13
閱讀 2472·2021-09-22 15:48
閱讀 2347·2019-08-29 17:19
閱讀 2598·2019-08-26 11:50
閱讀 1574·2019-08-26 10:37
閱讀 1741·2019-08-23 16:54
閱讀 2928·2019-08-23 14:14