成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

文件下載那點(diǎn)事

PascalXie / 1739人閱讀

摘要:不過(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.open

window.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

相關(guān)文章

  • 移動(dòng)端鍵盤(pán)和光標(biāo)的兼容點(diǎn)事

    摘要:解決方法如果使用頁(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以及以下...

    XboxYan 評(píng)論0 收藏0
  • 移動(dòng)端鍵盤(pán)和光標(biāo)的兼容點(diǎn)事

    摘要:解決方法如果使用頁(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以及以下...

    Kerr1Gan 評(píng)論0 收藏0
  • 移動(dòng)端鍵盤(pán)和光標(biāo)的兼容點(diǎn)事

    摘要:解決方法如果使用頁(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以及以下...

    Jackwoo 評(píng)論0 收藏0
  • 關(guān)于性能優(yōu)化的點(diǎn)事——函數(shù)防抖

    摘要:函數(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事件, 然...

    Stardustsky 評(píng)論0 收藏0
  • 關(guān)于var,let,const的點(diǎn)事

    摘要:一直使用定義變量,的出現(xiàn)給變量定義增加了兩個(gè)大將,。聲明的變量,塊作用域,不重復(fù)聲明覆蓋,限制了變量的作用域,保證變量不會(huì)去污染全局變量,所以盡量將改為用。 一直使用var定義變量,ES6的出現(xiàn)給變量定義增加了兩個(gè)大將let,const。那它們有什么區(qū)別呢。 1、const關(guān)鍵字它的作用就是定義一個(gè)常量,一旦定義無(wú)法更改,不能重復(fù)聲明覆蓋; showImg(https://segmen...

    KavenFan 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<