React中使用fetch實現檔案上傳下載

斜月明寒草發表於2018-11-18

在最近的專案中需要實現檔案上傳下載功能,在以前spring、jsp的專案中實現檔案上傳很簡單,但現在前後端分離,前端使用React,後端使用Spring Boot,實現就沒那麼方便了。

前端React使用fetch而非傳統的XMLHttpRequest從後端獲取Json資料,那麼檔案上傳自然而然也要使用fetch了。

在react中使用fetch上傳檔案不難,程式碼如下:

<input type="file" onChange={this.handleUpload}/>
複製程式碼
handleUpload = (e) => {
	e.preventDefault();
    
    let file = e.target.files[0];
    const formdata = new FormData();
    formdata.append('file', file);
        
    for (var value of formdata.values()) {
        console.log(value);
    }
    
    const url = 'http://127.0.0.1:8080/file/upload';
    fetch(url, {
        method: 'POST',
        body: formdata,
        headers: {
            "Content-Type": "multipart/form-data"
        }
    }).then(response => return response.json();)
      .catch(error => console.log(error));
};
複製程式碼

上述實現使用了原生的fetch方法,沒有做任何的封裝,同時還使用了FormData物件。

在實際操作中,遇到了一個坑,在跨域請求時不能自定義頭部,需要去掉headers,否則POST請求會變成OPTIONS請求。

fetch實現檔案下載就要相對麻煩一些。

下載原理很簡單,就是模擬a標籤的點選下載,ajax 不支援下載檔案功能,是因為 ajax 只能用來傳輸字元型資料,所以在過去無法使用 ajax 來下載檔案。

fetch可以把 response 儲存為 blob,下載結束後,為這個 blob 建立一個 URL,跳轉到這個URL,或使用 anchor element with download property ,瀏覽器會彈出儲存框。如果檔案很大的話,還需要用到 filesystem API,因為 blob 是存在記憶體中的。

const params = {
    group: group,
    path: path
};
//可以根據需求傳特定的一些引數
const downloadUrl = 'http://127.0.0.1:8080/file/download';
fetch(downloadUrl, {
    method: 'POST',
    body: window.JSON.stringify(params),
    credentials: 'include',
    headers: new Headers({
        'Content-Type': 'application/json'
    })
}).then((response) => {
    response.blob().then( blob => {
        let blobUrl = window.URL.createObjectURL(blob);
        //不能直接建立一個<a>標籤
        // let a = document.createElement('a_id');
        let a = document.getElementById('a_id');
        //無法從返回的檔案流中獲取檔名
        // let filename = response.headers.get('Content-Disposition');
        let filename = 'file.txt';
        a.href = blobUrl;
        a.download = filename;
        a.click();
        window.URL.revokeObjectURL(blobUrl);
    });
}).catch((error) => {
    console.log(error);
});
複製程式碼
 <a id='a_id'></a>
複製程式碼

這樣就在React中使用fetch實現了檔案上傳下載,先這樣,有問題後面再補充。

相關文章