場景:
很多時候,前端存在需要從後端下載文件的情況,典型的就是導出excel表格。
一般存在兩種方式:
1,請求接口之後,直接打開請求該文件的地址,下載到本地。
2,請求接口之後,將獲取到的文件數據格式轉換之後,再下載到本地。
先說第一種:
很簡單,請求完接口之後,打開該文件的地址:
window.location.href = res.request.responseURL
responseURL這個地址其實和接口地址是一樣,直接打開它,就能默認下載到本地的下載路徑了。
非常方便,但是存在不足,比如不能修改文件的名稱。
而且,有些場景使用這種方式是行不通的,比如,很多管理系統,都是需要登錄的,既然要登錄,那就一般都會需要驗證每個請求是否安全,往往需要在header裏帶上token,後端纔會給你這個請求放行。
所以,這種方式,你請求接口之後,轉到這個鏈接,其實就是再請求了一次,這個時候你是不好在請求裏帶上token的,自然也就拿不到你要的文件。
所以,這個時候就要用第二種方式。
第二種方式:
第二種方式,就是正常的api請求,獲取到文件數據之後,在本地模擬一次點擊按鈕下載,不過這次下載不是再向後端請求一次api,而是把第一次請求api之後,後端返回的文件數據轉換成合適的格式之後下載下來。
exportFile(this.queryParam).then(res => {
if (res.status === 200) {
const xlsx = 'application/vnd.ms-excel'
const blob = new Blob([res.data], { type: xlsx })
const a = document.createElement('a') // 轉換完成,創建一個a標籤用於下載
// const name = res.headers['content-disposition']
// a.download = name.split('=')[1]
a.download = `${this.$t('menu.operatelog')}.xlsx`
a.href = window.URL.createObjectURL(blob)
a.click()
a.remove()
document.body.removeChild(a) //也可以這麼移除
// 直接打開下載文件的鏈接
// window.location.href = res.request.responseURL
}
})
代碼很容易看懂,這裏就不解釋了,說幾個需要提醒的地方。
1.不管是第一種方式還是第二種方式,儘量讓後端指定好文件的類型。當然,使用第二種方式,前端可以再次指定好文件類型。
2.這裏將獲取到的文件內容轉換成blob類型的數據,是最常見的下載文件數據的格式,當然還可以使用別的方式。
3.這裏創建a標籤取下載文件,還可以用別的方式,或者如果碰到瀏覽器兼容性的問題,可能需要個性化處理。
4.download這裏可以拿後端返回的文件名,也可以自己定義文件名,看你自己哪個方便一些。如果後端拿到的文件名是亂碼,建議直接在前端定義文件名。
5.最關鍵的是,下載文件亂碼的問題,很多人碰到,解決方法也很簡單。
export function exportFile (parameter) {
return axios({
url: `${api.file}/export`,
method: 'get',
data: parameter,
header: {
headers: { 'Content-Type': 'application/x-download' }
},
responseType: 'blob'
})
}
在請求接口的header裏一定要指定responseType爲blob,否則把返回的文件數據轉換成blob對象,blob是不認識的,就會出現亂碼。
歡飲補充。