背景:
新上線的一個功能,大家都做得比較辛苦。
同時,也收到使用者回報功能不好用。
問題描述:
回報的問題是,在導出的檔案名看不懂,一旦導出多了,不好找。如果下載下傳一個使用者再自己重新命名一下,又會影響效率。
根據檔案名不知道裡面的内容
這就很煩了,
不改下名,不好找導出的檔案。
改吧,又太麻煩。
使用者又能拿這個功能怎麼樣,隻能吐槽這個新功能不好用罷了
這是一個非功能的體驗問題。
直接原因:
沒有指定下載下傳檔案名,浏覽器使用了預設的命名政策:将url上的非法字元去掉,然後拼一下。如果得到的字元串太長,還會進行截斷處理。
原因分析:
使用者執行導出後,後端傳回的是一個包含了導出内容的oss位址,也就是一個Url。前端直接把這個url放到<a>标簽中。使用者點選進行下載下傳
下載下傳時的互動
這種情況下,浏覽器下載下傳時展示在狀态欄上的名字,浏覽器就自由發揮了,目前浏覽器的命名規則是将url上的非法字元去掉,然後拼一下。
下載下傳的檔案名
優化意見:
方案1:伺服器傳回導出内容的二進制流。由伺服器指定浏覽器導出的檔案名。
代碼實作:
/**
* 将二進制流寫入HttpServletResponse
*
* @param fileName 浏覽器下載下傳時彈出下載下傳框、展示在狀态欄中的檔案名
* @param response 承載傳回給浏覽器的對象
* @param workbook POI中定義的excel。承載了excel模型及存放的資料
* @throws IOException
*/
private static void downLoadExcelWithOutputStream(HttpServletResponse response, Workbook workbook, String fileName) throws IOException {
response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setHeader("content-Type", "application/vnd.ms-excel");
/**
* 如果檔案名是包含中文字元,需要進行編碼。否則,浏覽器下載下傳時檔案名會是亂碼
*/
response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8.name()));
ServletOutputStream servletOutputStream = response.getOutputStream();
workbook.write(servletOutputStream);
/**
* 關閉writer,釋放記憶體
*/
workbook.close();
servletOutputStream.flush();
/**
* 此處記得關閉輸出Servlet流
*/
IoUtil.close(servletOutputStream);
}
關鍵代碼
方案2:伺服器傳回存放下載下傳檔案的oss Url,前端指定浏覽器下載下傳檔案的檔案名。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>前端自定義下載下傳檔案名e</title>
</head>
<body>
待下載下傳的檔案:<input type="text" name="fileUrl" id="fileUrl" value='' ><br />
自定義檔案名:<input type="text" name="fileName" id="fileName" value=''><br/>
<button id='btn'>下載下傳</button><br />
<span id='status'></span><br />
</body>
<script>
var url=document.getElementById('fileUrl').value;
console.log(url);
document.getElementById('btn').onclick = function() {
document.getElementById('status').innerHTML = '下載下傳中';
fetch(url).then(res => res.blob().then(blob => {
var a = document.createElement('a');
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = document.getElementById('fileName').value;
a.click();
window.URL.revokeObjectURL(url);
document.getElementById('status').innerHTML = '下載下傳完成';
}));
};
</script>
</html>
把oss檔案以blob的方式下載下傳到目前頁,然後再建立a标簽
效果:
使用
确定優化方案
最終標明了方案2。
原因是方案2改動最小,可以快速響應及時解決使用者關心的問題。
思考
方案1:
優點:
- 可以由後端靈活自定義浏覽器下載下傳時的檔案名。沒有相容性問題
- 代碼實作簡單。代碼量少,實作簡單
缺點:
- 伺服器帶寬打滿後會影響其它功能的使用。伺服器寫資料到浏覽器會占用伺服器網卡的總帶寬,如果打滿,其它功能也用不了。可以把帶寬想象成一座橋,大檔案就像一個大卡車。
- 影響到伺服器的穩定性。大檔案生成及傳輸過程會持續占用伺服器記憶體。伺服器的記憶體是有限的,下載下傳大檔案的功能占用了,其它功能就不能正常工作了。
- 分布式環境中,增加了代碼的複雜度。Feign或RestTempate在處理位元組流時需要特殊的配置,在更新這些http客戶元件時,也需要驗證對這些已有功能的影響。
方案2: