前端Nuxt 下載 後端 Larvel 提供的 Excel Zip 等BinaryFileResponse 檔案
本篇主要解決後端Laravel 所以提供的BinaryFileResponse 檔案讓前端Nuxt可以正確下載並且賦予後端提供的檔案名稱
參考資料
https://stackoverflow.com/questions/70911768/laravel-axios-file-download
https://www.cnblogs.com/theblogs/p/17477046.html
首先,後端Laravel的部分
Excel的範例
假設今天要回傳的檔案是Laravel Excel產生的一個.xlsx檔案的話,我們通常會這樣做
1 |
Excel::download(new EXPORT_CLASS(),DOWNLOAD_FILE_NAME); |
EXPORT_CLASS是將資料處理成excel檔案的一個class,這邊就不多提,DOWNLOAD_FILE_NAME就是設定好要讓瀏覽器下載的檔案名稱
這時候如果適用post man 或者瀏覽器直接瀏覽這個後端URL都會直接下載到一個.xlsx檔案
那如果要讓前端正確下載到這個檔案名稱可以這樣做
1 |
Excel::download(new EXPORT_CLASS(),DOWNLOAD_FILE_NAME,\Maatwebsite\Excel\Excel::XLSX,['Access-Control-Expose-Headers'=>'Content-Disposition']); |
簡單解釋一下參數
第三個參數:\Maatwebsite\Excel\Excel::XLSX 代表要輸出是xlsx檔案
第四個參數是header,主要是要將Content-Disposition曝露出來前端Axios才能夠正確抓到檔案名稱
注意一下,這邊執行的Excel::download的會傳值是一個 Symfony\Component\HttpFoundation\BinaryFileResponse
如果後端API有自訂response格式也可以調整一下讓檔案回傳這支API符合BinaryFileResponse類型就可以
ZIP的範例
後端第二個範例是,如果要下載的是一個zip檔,我們可以這樣做
1 2 3 4 5 6 7 8 9 10 11 |
$file = tempnam(sys_get_temp_dir(),''); $tmp = explode('/',$file); $download_name = $tmp[count($tmp)-1].'.zip'; $zip = new ZipArchive(); if($zip->open($file,ZipArchive::CREATE | ZipArchive::OVERWRITE)){ $zip->addFromString(); //或 $zip->addFile(); } $zip->close(); return Response::download($file,$download_name,['Access-Control-Expose-Headers'=>'Content-Disposition']); |
說明一下幾件事情
1. tempnam 產出一個檔案在指定路徑底下,sys_get_temp_dir()則是取得當下系統的暫存檔資料夾,所以這樣子可以產生一個php的暫存檔
2. $download_name存下系統產生的這個暫存檔檔名不含路徑
3. $zip->addFromString(); 或是 $zip->addFile(); 就自行依照情況取用,可參考上方外部連結資訊
4. 最後Response::download 參數與Excel::download() 大致相同,都是記得在header中把Content-Disposition曝露出來即可
接著,前端的做法
Request部分
後端回傳的資料格式為BinaryFileResponse,前端再透過Axios呼叫的時候也記得指定responseType,例如以下
1 |
await axios.post(url,payload,{responseType: 'blob'}) |
那麽,拿到response之後,後端原本提供的檔案名稱可以在header中這樣取得
1 |
res.headers['content-disposition'].split("filename=")[1] |
Download部分
最後,要讓檔案下載的方式可以參考下方範例
1 2 3 4 5 6 7 8 |
let file_name = res.headers['content-disposition'].split("filename=")[1] file_name = file_name.substring(1,file_name.length) const url = window.URL.createObjectURL(new Blob([res.data])); const link = document.createElement('a'); link.href = url; link.setAttribute('download', file_name); //or any other extension document.body.appendChild(link); link.click(); |
同樣說明一下內容,首先拿到file_name之後,很神奇的資料會變成_XXX.zip 多了一個底下,因此用substring稍微處理了一下
剩下的邏輯就是在頁面上產生一個<a> Tag,並且把response放入,最後點擊連結讓瀏覽器下載檔案
以上