node實現文件下載不得不說的那些事兒

這幾天一直在作遠程文件下載的事,如今總算有了解決,特來記錄一下踩過的坑和想揍本身的心html

需求

  1. 應用場景是這樣的,底層邏輯數據請求接口是由Java寫的,也就是說原始文件存在Java服務端,返回時有加密措施
  2. 因爲工做須要,前端獲取數據操做須要node服務器作中間轉發
  3. Java接口使用post方式來請求下載
  4. 前端點擊下載後瀏覽器啓用內置下載器進行下載,並能看到進度以下圖所示
    圖片描述
先說總結,下附過程

前端GET下載和POST下載的對比

  1. 通常狀況下,若是是網盤應用或者不涉及多文件下載的場景(如本例中node做爲文件服務器,能夠直接與前端交互時),徹底能夠經過拼接GET請求url進行模擬點擊下載,系統開銷還小,響應快。若是像本例中這樣的場景會遇到這樣一個問題,詳見連接
  2. 當請求參數過長或爲了安全,就須要用到POST下載。

最終採用的方案

  • 前端經過模擬表單提交POST請求
  • node端經過piperesponseAresponseB串聯起來,如responseA.pipe(responseB)
  • Done

最開始的思路

最開始沒搞清楚怎麼用POST請求下載且前端該怎樣接收和處理,關鍵字node 前端下載搜到的絕大多數都是用GET連接下載,加上剛剛接觸node沒有很好理解流的概念,所以一根筋的想如何經過POST請求轉換成GET請求下載,因而自做主張採用了笨辦法,走上了一條差點沒回來的路:前端

  1. 前端點擊下載,發送post請求Anode
  2. node獲取參數向Java端發送post請求B把文件先下載到node本地(Java返回的記爲responseA)並用responseB返回前端文件地址文件名
  3. 前端獲取到responseB後拼接成get請求模擬a標籤點擊去下載node中的文件
  4. 下載完成後再將node端對應文件刪除。

寫到這裏本身都忍不住想錘本身,給本身挖坑不說,這樣來回請求下載,流量double,真的是敗家。node

涉及的知識點

  • angular前端訪問node跨域設置
    在前端項目根目錄下新建 proxy.conf.json文件,配置接口轉發
    {
        "/api": {
            "target" : "http://localhost:3000"//server端port
        }
    }
    保存後,配置 package.json文件裏 start命令以下,保存後從新運行就好
    "start": "ng serve --proxy-config proxy.conf.json",
  • node如何發送get/post請求
  • stream、buffer的概念:文章一 文章二
  • 前端GET下載的三種方式ios

    1. 直接將拼接好的GET請求url賦值給a標籤,模擬點擊
    2. 先獲取數據流存進blob對象,a.href = window.URL.createObjectURL(blob)git

      每次調用 createObjectUR的時候,一個新的URL對象就被建立了.即便你已經爲同一個文件建立過一個URL. 若是你再也不須要這個對象,要釋放它,須要使用 URL.revokeObjectURL()方法. 當頁面被關閉,瀏覽器會自動釋放它,可是爲了最佳性能和內存使用,當確保再也不用獲得它的時候,就應該釋放它.
    3. 新建一個隱藏的iframesrc設置爲如上一步的url便可
  • 前端如何接收文件流並下載github

    原生 xhr請求寫法
    var xhr = new XMLHttpRequest();    
        xhr.open("get", url, true);
        xhr.responseType = "blob";
        xhr.onload = function() {
            if (this.status == 200) {
                var blob = this.response;
                var img = document.createElement("img");
                img.onload = function(e) {
                  window.URL.revokeObjectURL(img.src); 
                };
                img.src = window.URL.createObjectURL(blob);
           $("#imgcontainer").html(img);
     } } xhr.send();
    axios請求寫法
    axios.post("/api/download_reports",msgArr,{
        responseType:'blob',
        onDownloadProgress (a){
            //監聽下載進度
            if(a.lengthComputable){
                let percent = (a.loaded*100/a.total).toFixed(2)
                console.log(percent)
                $('#percent').html(tempLoaded)
            }
        }
    })
    .then(response => {
        console.log(response)
        if(response.status == 200){
            const blob = new Blob([response.data],{type: 'application/octet-stream'});
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = baseName+'.zip';
            document.body.appendChild(a);
            a.click();
            document.body.removeChild(a);
            window.URL.revokeObjectURL(url);
        }
    })
    .catch(error => {
        console.log(error)
    })
  • 前端如何獲取下載進度,並進一步完成進度條設置ajax

    axios.post('/喵',postData, {
        onUploadProgress (a){
        //上傳進度同理
            console.log(a)
        },
        onDownloadProgress (a){
        //控制檯輸出後,能夠發現咱們可以經過a.loaded*100/a.total來得到下載進度
        //但需注意的是若是node端的responseB沒有設置'Content-Length'即二進制流size的話
        //axios.post此時獲取到的下載進度事件對象a裏lengthComputable爲false,進而a.total=0
        //進而沒法獲取百分比進度
            console.log(a)
        }
    })
  • 前端POST下載的兩種方式json

    這個沒有什麼好說的,惟一可能要注意的就是表單裏input傳參的時候,若是參數比較多,能夠用JSON.stringify()轉換,只向後端發送一個字符串就好

以上就是本身對node實現文件前端下載的一些理解,若有不妥歡迎交流指正~axios

相關文章
相關標籤/搜索