距離上次博文更新已經快一個月了,期間忙於各種事情無法脫身。今天難得閒暇 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貼一下,有興趣的同學可以下載下來跑一下溜溜