關(guān)于前端 vue 導(dǎo)出功能嗅骄,blob,Content-Disposition饼疙,json溺森,fileName

導(dǎo)出現(xiàn)狀

  • 大型項目,有文件管理窑眯,前臺導(dǎo)出請求會被后臺寫入到文件管理屏积,可能有權(quán)限和記錄需求
  • 一般項目,直接返回流磅甩,但通常會做為兩個接口炊林。前端調(diào)用導(dǎo)出校驗成功后,再調(diào)用導(dǎo)出流接口
  • 當(dāng)前方案:后端查詢直接成功直接返回blob卷要,異常返回json渣聚,后臺返回值類型不一致也會報錯

Q:問題

  • 后端成功會返回流独榴,失敗返回json,但因為 axios 請求時聲明了 responseType: 'blob'奕枝,所以返回值會被處理為blob棺榔,通過導(dǎo)出方法,會將json直接導(dǎo)出為 Excel

  • 文件名處理隘道,以方法傳入為優(yōu)先級症歇,若無取 Content-Disposition 返回 fileName,若無取默認(rèn)值

A:答案

  • 若后臺返回不是成功谭梗,給出報錯提示忘晤,而不是直接導(dǎo)出為 Excel(默認(rèn)是這樣子)
  • 獲取到后臺 Header 的 Content-Disposition,作為導(dǎo)出文件名稱

S:方案

  1. 獲取到后臺 Header 的 Content-Disposition激捏,作為導(dǎo)出文件名稱

    • 主要是后臺調(diào)整设塔,java為例。首先要設(shè)置header缩幸,因為返回流就不會返回json了
    • 其次是要設(shè)置response header 暴露給前端訪問壹置。不設(shè)置在瀏覽器查看有,js訪問會為空

備注:設(shè)置需要在 write 前賦值

response.reset(); // 重置輸出流
response.setContentType("application/vnd.ms-excel;charset=UTF-8"); //通知客服文件的MIME類型
//設(shè)置要下載的文件的名稱: 若是中文需要轉(zhuǎn)碼, java亂碼為 ?????
response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(sheetName, "utf-8"));
// 服務(wù)端要在header設(shè)置Access-Control-Expose-Headers, 前端才能正常獲取到
response.setHeader("Access-Control-Expose-Headers", "Content-Disposition");
  1. 若后臺返回不是成功表谊,給出報錯提示钞护,而不是直接導(dǎo)出為 Excel(默認(rèn)是這樣子)- 文件名稱處理

2.1 在返回 aop 處理導(dǎo)出

// 響應(yīng)攔截器
http.interceptors.response.use(
  async response => {
    function formatResponse(insertFragment) {
      _interceptorsLoadingAndMessage();
      insertFragment && insertFragment();
      return response.data;
    }
    // 文件Excel導(dǎo)出: NOTE: 處理請求聲明的blob是否為json
    if (response.config.conf[KEY_EXPORT_TYPE]) {
      const res = await _fileToJson(response.data);
      if (!res.message) {
        response.data = res.data;
      } else {
        // 處理文件名稱: <詳見 http://www.reibang.com/p/9352c68a0635>
        let fileName;
        try {
          const disposition = response.headers["content-disposition"];
          fileName = decodeURIComponent(disposition.split("fileName=")[1]); // 中文需要轉(zhuǎn)碼 (前端亂碼為百分號形式)
        } catch (error) {
          fileName = "導(dǎo)出文件";
        }
        if (!fileName.includes(".xls")) fileName += ".xls";
        return { data: formatResponse(), fileName }; // 格式化輸出
      }
    }
    const msg = response.data.msg || response.data.message;
    const code = Number(response.data.code);
    if (code === CODE_SUCCESS) {
      return formatResponse(() => {
        // 需要show成功Message信息
        if (response.config.conf[KEY_SHOW_MESSAGE])
          progress.showSuccessMessage(msg);
      });
    }
    // 請求報錯: 顯示成功的 Toast 提示
    if (code === CODE_FINALLY) {
      return Promise.reject(
        formatResponse(() => progress.showSuccessMessage(msg))
      );
    }
    // 登錄失效跳轉(zhuǎn)登錄頁面. NOTE: 注意可能導(dǎo)致循環(huán)調(diào)用
    if (code === CODE_INVALID) {
      progress.invalidToken(msg || TIP_INVALID_TOKEN);
    }
    // 請求結(jié)束loading和error處理
    return _interceptorsLoadingAndMessage(
      new Error(msg || TIP_ERROR_MESSAGE),
      !response.config.conf[KEY_NO_ERROR_TIP]
    );
  },
  error => {
    return _interceptorsLoadingAndMessage(error);
  }
);

2.2 將返回值格式為json,驗證返回是否為流類型

// 將blob對象轉(zhuǎn)化為json(文件類型調(diào)用ajax 取后端的返回值做特殊處理)
function _fileToJson(file) {
  let data = {},
    message = "";
  function formatReturn() {
    return { data, message };
  }
  return new Promise(resolve => {
    const reader = new FileReader();
    reader.onload = res => {
      const { result } = res.target; // 得到字符串
      try {
        // 解析成json對象
        data = JSON.parse(result);
      } catch (err) {
        message = err.message || err;
      }
      resolve(formatReturn());
    }; // 成功回調(diào)
    reader.onerror = err => {
      message = err.message || err;
      resolve(formatReturn());
    }; // 失敗回調(diào)
    reader.readAsText(new Blob([file]), "utf-8"); // 按照utf-8編碼解析
  });
}
  1. 通用前端 blob 導(dǎo)出方式
/** 4.Excel:報表blob導(dǎo)出 */
request.exportExcel_blob = function(res = {}, fileName) {
  const blob = new Blob([res.data], {
    type: 'application/vnd.ms-excel;charset=UTF-8',
  });
  const link = document.createElement('a');
  link.style.display = 'none';
  link.href = URL.createObjectURL(blob);
  link.download = fileName || res.fileName; // 下載后文件名: 攔截器處理 content-disposition, 傳入優(yōu)先
  document.body.appendChild(link);
  link.click();
  URL.revokeObjectURL(link.href);
  document.body.removeChild(link);
};
  1. **至此就可以封裝出通用的Excel接口
/** 5.Excel:報表blob導(dǎo)出 */
request.exportExcel = async function(url, params = {}, fileName) {
  const res = await request.postData(url, params, {
    [KEY_EXPORT_TYPE]: 'blob',
  });
  return this.exportExcel_blob(res, fileName);
};

2021.03.05 真是一個執(zhí)著的人爆办,為了這個問題研究了差不多1天难咕,記錄一下學(xué)習(xí)真好,開心 ~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末距辆,一起剝皮案震驚了整個濱河市余佃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌跨算,老刑警劉巖爆土,帶你破解...
    沈念sama閱讀 217,277評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異诸蚕,居然都是意外死亡步势,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評論 3 393
  • 文/潘曉璐 我一進(jìn)店門背犯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來坏瘩,“玉大人,你說我怎么就攤上這事漠魏【蠓” “怎么了?”我有些...
    開封第一講書人閱讀 163,624評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長哪自。 經(jīng)常有香客問我丰包,道長,這世上最難降的妖魔是什么提陶? 我笑而不...
    開封第一講書人閱讀 58,356評論 1 293
  • 正文 為了忘掉前任烫沙,我火速辦了婚禮,結(jié)果婚禮上隙笆,老公的妹妹穿的比我還像新娘锌蓄。我一直安慰自己,他們只是感情好撑柔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評論 6 392
  • 文/花漫 我一把揭開白布瘸爽。 她就那樣靜靜地躺著,像睡著了一般铅忿。 火紅的嫁衣襯著肌膚如雪剪决。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,292評論 1 301
  • 那天檀训,我揣著相機(jī)與錄音柑潦,去河邊找鬼。 笑死峻凫,一個胖子當(dāng)著我的面吹牛渗鬼,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播荧琼,決...
    沈念sama閱讀 40,135評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼譬胎,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了命锄?” 一聲冷哼從身側(cè)響起堰乔,我...
    開封第一講書人閱讀 38,992評論 0 275
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎脐恩,沒想到半個月后镐侯,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,429評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡驶冒,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評論 3 334
  • 正文 我和宋清朗相戀三年析孽,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片只怎。...
    茶點(diǎn)故事閱讀 39,785評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖怜俐,靈堂內(nèi)的尸體忽然破棺而出身堡,到底是詐尸還是另有隱情,我是刑警寧澤拍鲤,帶...
    沈念sama閱讀 35,492評論 5 345
  • 正文 年R本政府宣布贴谎,位于F島的核電站汞扎,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏擅这。R本人自食惡果不足惜澈魄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望仲翎。 院中可真熱鬧痹扇,春花似錦、人聲如沸溯香。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,723評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽紧憾。三九已至反惕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間湿镀,已是汗流浹背炕吸。 一陣腳步聲響...
    開封第一講書人閱讀 32,858評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留勉痴,地道東北人赫模。 一個月前我還...
    沈念sama閱讀 47,891評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像蚀腿,于是被迫代替她去往敵國和親嘴瓤。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評論 2 354

推薦閱讀更多精彩內(nèi)容