需求分析: 因為axios在請求時定制了很多個性化需求,比如攜帶token嘲玫,比如指明服務(wù)器域名等等,如果采用相對地址href的請求方式以及部分框架自帶的文件上傳方式征冷,是無法滿足需求的漓帅,我們的目的是采用相同的get和post完成文件下載和上傳工作
下面直接分享解決方案
//文件上傳, 相對簡單些芬首,返回的都是json數(shù)據(jù)
submitUpload() {
if(!this.checkUpload()) return false
let fileFormData = new FormData();
//this.file 更具不同ui框架獲取的file對象,this.file.raw文件的二進(jìn)制流
fileFormData.append('file', this.file.raw);
let requestConfig = {
//重新設(shè)置請求頭,考慮服務(wù)器處理時間可能過長,加大timeout
headers: {
'Content-Type': 'multipart/form-data',
timeout: 20000,
},
}
this.$axios.post(this.url, fileFormData, requestConfig).then(() => {
this.$message({
message: '文件上傳成功',
type: 'success',
duration: 1500,
onClose: () => {
//文件上傳已經(jīng)做成了組件.vue,向父類組件發(fā)送done消息,用于更新table等
this.$emit('done')
}
})
})
},
//文件下載
//重點:一切正常,返回的是blob數(shù)據(jù),創(chuàng)建一個a標(biāo)簽下載文件
//難點:如果服務(wù)器報,返回的可是一個json數(shù)據(jù),特殊處理提取出來
download(){
this.$axios.get(this.url, {
responseType: 'blob', // important
timeout: 20000,
}).then((response) => {
//返回的是一個錯誤
if(response.headers['content-type']==='application/json'){
//提取錯誤的json消息并轉(zhuǎn)換(此時json消息依舊在response.data中,這是一個blob數(shù)據(jù))
let reader = new FileReader();
reader.onload = e => this.$message.error(JSON.parse(e.target.result).msg);
reader.readAsText(response.data);
return false;
}
//接收的是文件,fileName是一個property,設(shè)置了默認(rèn)值(比如"文件模版.xls")
let fileName = this.fileName;
//服務(wù)器返回的請求頭中包含了文件名信息,提取出來
//可能出現(xiàn)的BUG:如果在響應(yīng)頭中能看到"content-disposition",axios拿到的response卻沒有,
//這不怪axios,你需要去服務(wù)器設(shè)置一個叫Access-Control-Expose-Headers的東西
//讓它包含"content-disposition"
if(response.headers["content-disposition"]){
const patt = new RegExp("filename=([^;]+\\.[^\\.;]+);*");
const result = patt.exec(response.headers["content-disposition"]);
if(result.length>1){
//中文解碼
fileName = decodeURI(result[1]);
}
}
//制作a標(biāo)簽并點擊下載
const url = window.URL.createObjectURL(new Blob([response.data],
{ type: 'application/octet-stream' }));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', fileName);
document.body.appendChild(link);
link.click();
});
總結(jié): 文件上傳在于獲得文件二進(jìn)制流并制作成FormData進(jìn)行post請求到踏,同時header需設(shè)置Content-Type='multipart/form-data'。
而文件下載則更復(fù)雜些泻红,需從response.data中獲得blob(文件二進(jìn)制流)創(chuàng)建本地的下載標(biāo)簽a夭禽,最后點擊下載,同時還需注意如果發(fā)生錯誤谊路,服務(wù)器返回的是json數(shù)據(jù),該數(shù)據(jù)依舊存在于response.data并以blob形式存在菩彬,需特殊處理提取出來并解析缠劝。
以上,依照不重復(fù)造輪子原則骗灶,可以把這兩類分別做成兩個組件惨恭,合理利用<slot>標(biāo)簽和property屬性做到代碼寫一次,到處可復(fù)用原則耙旦。