javascript Blob對象實現(xiàn)文件下載
說明
最近遇到一個需求,文件下載,但需要鑒權(quán),這就意味著不能用后臺返回下載鏈接的方式進(jìn)行下載,因為一旦被別人拿到這條鏈接,就可以不需要任何權(quán)限就直接下載,因此需要換種思路,在一番百度之后,了解到了blob對象,這就是本文要講的內(nèi)容
注意:本文僅為記錄學(xué)習(xí)軌跡,如有侵權(quán),聯(lián)系刪除
一、Blob對象
Blob 對象表示一個不可變、原始數(shù)據(jù)的類文件對象。它的數(shù)據(jù)可以按文本或二進(jìn)制的格式進(jìn)行讀取,也可以轉(zhuǎn)換成 ReadableStream 來用于數(shù)據(jù)操作。
二、前端
blob下載思路:
1) 使用ajax發(fā)起請求,指定接收類型為blob(responseType: ‘blob')
2)讀取請求返回的頭部信息里的content-disposition,返回的文件名就在這里面(或者自定義文件名,可跳過此步驟)
3)使用URL.createObjectURL將請求的blob數(shù)據(jù)轉(zhuǎn)為可下載的url地址
4)使用a標(biāo)簽下載
代碼:
// 下載
export function download(query,newFileName) {
return request({
url: '/file/download',
method: 'get',
responseType: 'blob',
params: query
}).then((res) => {
/**
* blob下載思路
* 1) 使用ajax發(fā)起請求,指定接收類型為blob(responseType: 'blob')
* 2)讀取請求返回的頭部信息里的content-disposition,返回的文件名就在這里面(或者自定義文件名,可跳過此步驟)
* 3)使用URL.createObjectURL將請求的blob數(shù)據(jù)轉(zhuǎn)為可下載的url地址
* 4)使用a標(biāo)簽下載
*
*/
let blob = res.data
// 從response的headers中獲取filename, 后端response.setHeader("Content-disposition", "attachment; filename=xxxx.docx") 設(shè)置的文件名;
// let patt = new RegExp('filename=([^;]+\\.[^\\.;]+);*')
// let contentDisposition = decodeURI(res.headers['content-disposition'])
// let result = patt.exec(contentDisposition)
// let fileName = result[1]
//將請求的blob數(shù)據(jù)轉(zhuǎn)為可下載的url地址
let url = URL.createObjectURL(blob)
// 創(chuàng)建一個下載標(biāo)簽<a>
const aLink = document.createElement('a')
aLink.href = url
// 2.直接使用自定義文件名,設(shè)置下載文件名稱
aLink.setAttribute('download', newFileName )
document.body.appendChild(aLink)
// 模擬點(diǎn)擊下載
aLink.click()
// 移除改下載標(biāo)簽
document.body.removeChild(aLink);
})
}
調(diào)用該方法
//下載
download(row) {
// filePath:文件路徑,例如:e:\upload\
// fileName:文件名, 例如:a.xlsx
let form = {
filePath: row.filePath,
fileName: row.fileName,
};
//下載,row.fileOriginalName是文件的原始名稱,僅僅用于文件下載時起個名字而已
download(form, row.fileOriginalName);
}
// 由于本人使用的是阿里的oss服務(wù),所以只需要傳個文件路徑回去后端,根據(jù)文件路徑查詢oss接口得到返回的文件流即可,例如(BufferedInputStream),在響應(yīng)頭設(shè)置好返回的類型即可
三、后端
后端這里用了阿里的oss服務(wù),直接拿到文件流(new BufferedInputStream(ossObject.getObjectContent())),如果是非oss的情況下,只需要讀取對應(yīng)服務(wù)器上面的文件(File),轉(zhuǎn)成BufferedInputStream后,直接套用下面的代碼即可(即通過response.getOutputStream()設(shè)置BufferedOutputStream 就行了)
// response:響應(yīng)
// filePath:文件路徑,例如:e:\upload\
// fileName:文件名, 例如:a.xlsx
public void download(HttpServletResponse response, String filePath, String fileName) {
//待下載文件名
response.reset();
response.setHeader("Content-Disposition", "attachment;filename=" + fileName);
response.setContentType("application/octet-stream");
response.setCharacterEncoding("utf-8");
// 創(chuàng)建OSSClient實例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// ossObject包含文件所在的存儲空間名稱、文件名稱、文件元信息以及一個輸入流。
OSSObject ossObject = ossClient.getObject(bucketName, filePath + "/" + fileName);
BufferedInputStream in = null;
BufferedOutputStream out = null;
byte[] buff = new byte[1024];
int length = 0;
try {
in = new BufferedInputStream(ossObject.getObjectContent());
out = new BufferedOutputStream(response.getOutputStream());
while ((length = in.read(buff)) != -1){
out.write(buff,0,length);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if(out != null){
try {
out.flush();
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(in != null){
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (ossClient != null) {
ossClient.shutdown();
}
}
}
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
?JavaScript?數(shù)據(jù)結(jié)構(gòu)之散列表的創(chuàng)建(1)
這篇文章主要介紹了?JavaScript?數(shù)據(jù)結(jié)構(gòu)之散列表的創(chuàng)建,文章圍繞主題相關(guān)內(nèi)容展開詳細(xì)的介紹,需要的小伙伴可以參考一下2022-04-04
67 個節(jié)約開發(fā)時間的前端開發(fā)者的工具、庫和資源
在本文中,我不會去談 React、Angular、Vue 等等這些大的前端框架,也不會談 Atom、VS code、Sublime 等等這些已經(jīng)很出名的代碼編輯器,我只是想簡單的分享一套我認(rèn)為有助于提升開發(fā)者工作流的工具集2017-09-09

