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