因公司架構緣由前端請求須要通過NodeJs進行接口轉發再返回到瀏覽器,在對導出Excel接口進行代理請求時發現導出到瀏覽器的數據出現亂碼的狀況,一頓操做最後發現是編碼的問題。javascript
即使java後端已經對數據作了處理,經node接口請求響應以後文件流的編碼仍是被修改了,以前一直想着應該以一對一的請求響應處理方式去獲取最原始的數據的心理設定做祟,不該對響應response作處理,而是應該直接拿到什麼返回什麼。一直沒往編碼問題方向去思考,一番折騰甚至使用了三種不一樣的請求方式仍是返回亂碼數據,不由開始懷疑本身這幾年前端是否是白作了,還適合作開發嗎??是否是該轉行去送外賣了...前端
排錯思路:java
使用postman直接請求後端接口,不通過nodeJs轉發。複製postman請求後生成的curl命令代碼,打開命令行工具進行粘貼,並在最末尾添加-o test_java.xls
後回車,將請求獲得的文件流保存爲Excel後打開查看的方式看看是否是java後端的接口自己就有問題,我這裏打開後發現數據工工整整排列整齊...node
打開瀏覽器控制檯並切換到network模塊下,右鍵移動到Copy選項,點擊Copy as cURL
,仿造上一步在命令最末尾追加-o test_nodeJs.xls
打開文件查看是否出現亂碼,我在這一步發現打開後的文件全是亂碼...問題就出在NodeJs對後端接口的請求上ios
假設上面兩步打開以後發現文件均沒有問題,那麼就是前端客戶端對文件流的處理代碼邏輯上有問題json
如下是個人客戶端代碼,沒有問題...axios
建立a標籤並模擬點擊事件下載Excel文件後端
if (isBlob(res.data)) {
const filename = decodeURIComponent(
headers['content-disposition'].match(/(filename=(.*))/)[2]
); // 服務端須要在響應頭設置 Content-Disposition
const blob = new Blob([res.data], {
type: 'application/octet-stream',
});
const linkNode = document.createElement('a');
linkNode.download = filename;
linkNode.style.display = 'none';
linkNode.href = URL.createObjectURL(blob);
document.body.appendChild(linkNode);
linkNode.click();
URL.revokeObjectURL(linkNode.href);
document.body.removeChild(linkNode);
} else {
// 導出失敗
}
複製代碼
nodeJs採用的是egg框架,如下三種請求方式在前期沒有沒有設置編碼的時候均是返回亂碼。後續在發現問題點以後通過修改都能成功獲取到一個Buffer緩存,直接往瀏覽器端返回便可。我採用的是axios的方案,無他,就是對這個庫比較熟而已,在不一樣環境下可能會出現請求響應不一致的狀況,這裏將三種請求都分享給你們promise
const axios = require('axios');
const rp = require('request-promise');
/** * 方案1 egg內置的curl請求 * 關鍵配置:不設置dataType屬性 * dataType的做用是明確告訴 HttpClient 以 xml等文本 格式處理返回的響應 body,設置爲‘json’ ,以 JSON 格 * 式處理返回的響應 body * 不設置dataType:默認 HttpClient 不會作任何處理,會直接返回 Buffer 類型數據 */
const result = await ctx.curl(requestURI, {
method: 'POST',
timeout: 60000,
data: JSON.stringify(body),
});
ctx.set({
'Access-Control-Expose-Headers': 'Content-Disposition',
'content-disposition': result.headers['content-disposition'],
});
ctx.body = result.data;
/** * 方案2 axios * 關鍵配置: responseType: 'arraybuffer', responseEncoding: 'binary' */
const result = await axios({
method: 'POST',
url,
params: queryParams,
data: body,
responseType: 'arraybuffer',
responseEncoding: 'binary',
});
ctx.set({
'Access-Control-Expose-Headers': 'Content-Disposition',
'content-disposition': result.headers['content-disposition'],
});
ctx.body = result.data;
/** * 方案3 request-promise * 關鍵配置: encoding: null, * 設置encoding爲binary仍是會亂碼,後續發如今stack overflow上發現設置爲null能解決問題 * address:https://stackoverflow.com/questions/48752822/request-promise-download-pdf-file/48753392#48753392 */
const result = await rp({
method: 'POST',
uri: requestURI,
body: JSON.stringify(body),
resolveWithFullResponse: true,
encoding: null,
});
ctx.set({
'Access-Control-Expose-Headers': 'Content-Disposition',
'content-disposition': result.headers['content-disposition'],
});
ctx.body = result.body;
複製代碼
謹以此文,記念這次開發導出Excel功能中遇到的問題瀏覽器
路漫漫其修遠兮,吾將上下而求索