距離上次博文更新已經快一個月了,期間忙於各種事情無法脫身。今天難得閒暇 and then 就來更新啦...
上篇中我們瞭解了下載React中如何實現文件的上傳,雖然不算什麼高大上的技術但實際開發的時候會讓自己更加的遊刃有餘。今天繼續更新另一個相關的技術 --> 文件的下載
看過上篇博文的朋友應該有印象,做文件上傳的功能可以用Form表單
、fetch
(Ajax或者Axios都行)和Form+fetch
這三個方法。後臺採用express框架,由於fetch請求會涉及到跨域問題,所以後臺還使用了Cors中間件來解決跨域的問題。這一點在上篇博文中都有提及所以在這裏就不加贅述。
本篇所說的文件下載也是基於Form
和fetch
(Ajax或者Axios都行)。且聽慢慢道來...
Form
Form表單可謂是前端界的萬金油,什麼數據提交、上傳下載都樣樣精通,最關鍵的是:不需要考慮跨域
。
利用Form表單進行文件下載很簡單,只需要幾行代碼就可以搞定:
class FormDownload extends Component {
render() {
return (
<form method="get" action="http(s)://下載文件的後臺接口">
<button type="submit">Download!</button>
</form>
)
}
}
export default FormDownload;
只要這一小段代碼就可以實現文件的下載,是不是很開森?
Fetch
利用Fetch實現文件下載相比於Form那就顯得很麻煩也很囉嗦,爲什麼呢?上代碼先
class FetchDownload extends Component {
download = () => {
fetch('http(s)://下載文件的後臺接口').then(res => res.blob().then(blob => {
let a = document.createElement('a');
let url = window.URL.createObjectURL(blob);
let filename = res.headers.get('Content-Disposition');
if (filename) {
filename = filename.match(/\"(.*)\"/)[1]; //提取文件名
a.href = url;
a.download = filename; //給下載下來的文件起個名字
a.click();
window.URL.revokeObjectURL(url);
a = null;
}
}));
};
render() {
return (
<input type="button" value="下載" onClick={this.download}/>
)
}
}
export default FetchDownload;
麻煩在哪兒:
1、需要考慮跨域問題
2、需要對返回值進行轉化
3、需要有DOM操作(生成a標籤和銷燬a標籤)
下面就一起來看看具體操作步驟:
- 用fetch訪問後臺接口並接受後臺返回值。因爲fetch方法返回一個Promise對象,因此我們可以在then用獲取到它的返回值
- 這一步就厲害了。fetch的返回值是一個
有意思的對象
,它包含了很多方法,其中一個方法就是blob()。這個方法可以將fetch的返回值轉化成Blob對象。 - 利用
document.createElement
創建一個a
標籤 - 利用
window.URL.createObjectURL
將blob數據轉成對應url
。 - 通過fetch的響應頭獲取到文件名
res.headers.get('Content-Disposition')
。這裏需要mark下,因爲我們後臺使用了Cors中間件來解決跨域問題,因此需要做特別的設置來讓Cors將響應頭給暴露出來'exposedHeaders': '*'
,具體的大家可以看後臺代碼。 - 接下來就是對a標籤的一系列操作,然後模擬點擊事件觸發下載動作。
- 最後需要將轉化出來的url進行銷燬
window.URL.revokeObjectURL(url)
,a標籤置爲null
看完整個過程,除了瞭解到前面所說的麻煩
,我們依然要看到其優點所在。對於Form實現的下載功能,我們只能
做下載,而不能做額外
的事情;但是使用fetch我們可以將獲取到的數據做更多的處理,自由度相對較高。
總結
目前這方面的輪子特別多而且很是花裏胡哨(但是用的特別爽,真香系列!),不過最基礎的往往也就這麼點技術。萬丈高樓平地起,學好基礎何怕不會造輪子。。。哈哈。另外再把demo貼一下,有興趣的同學可以下載下來跑一下溜溜