http-proxy-middleware onProxyRes中文數據亂碼的解決方案

onProxyRes相關代碼:

option.onProxyRes = function (proxyRes: any, req: any, res: any) {
        // 參考:https://www.jianshu.com/p/f8ac6e813b96
        const oriWriteHead = res.writeHead;
        const oriWrite = res.write;
        const oriEnd = res.end;
        let chunks: any = [];
        let size = 0;
        Object.assign(res, {
            writeHead: () => {},
            write: (chunk: any) => {
                chunks.push(chunk);
                size += chunk.length;
            },
            end: () => {
                let oriBuffer = Buffer.concat(chunks, size);
                console.log('buffer:', oriBuffer);
                console.log('************');
                console.log(oriBuffer.toString());
                console.log('************');
                const buffer = Buffer.concat(chunks, size); // 一定要轉成buffer,buffer長度和string長度不一樣
                const headers = Object.keys(proxyRes.headers)
                    .reduce((prev, key) => {
                        const value = key === 'content-length' ? buffer.length : proxyRes.headers[key];
                        return Object.assign({}, prev, {[key]: value});
                    }, {});
                oriWriteHead.apply(res, [200, headers]);
                oriWrite.call(res, buffer);
                oriEnd.call(res);
            }
        });
};

當接口返回數據不包含中文時,可以正常打印數據
在這裏插入圖片描述
當接口數據包含中文時,發現亂碼了:
在這裏插入圖片描述

查詢過很多解決方案都沒辦法解決這個問題,嘗試過的解決方法:

  • 利用Buffer.concat
  • 利用iconv-lite decode

解決方案

觀察接口響應header,發現了這樣一個字段:

content-encoding: gzip

瞬間就聯想到是不是代理的數據是被壓縮過的,於是查看node如何解壓縮gzip數據,發現了zlib這個包,對接收到的chunk數據進行gunzip之後發現能夠正常解析數據了。

還是前文的代碼,在end函數中對oriBuffer進行處理:

let oriBuffer = Buffer.concat(chunks);
const compressBuffer = handleBuffer(oriBuffer,proxyRes.headers['content-encoding'], handleJsonResFunc);

handleBuffer方法如下:

const zlib = require('zlib');
/**
 * 根據Content-Encoding消息頭確定解碼方式,處理完數據之後再編碼回去
 * @param oriBuffer
 * @param encoding 消息頭中的編碼格式
 * @param handleJsonResFunc
 */
function handleBuffer(oriBuffer: Buffer, encoding: string, handleJsonResFunc: Function) {
    let decodeMethod: string = '';
    let encodeMethod: string = '';
    // 編碼格式介紹:https://developer.mozilla.org/zh-CN/docs/Web/HTTP/Headers/Content-Encoding
    switch (encoding) {
        case 'gzip':
            decodeMethod = 'gunzipSync';
            encodeMethod = 'gzipSync';
            break;
        case 'deflate':
            decodeMethod = 'inflateSync';
            encodeMethod = 'deflateSync';
            break;
        case 'br':
            decodeMethod = 'brotliDecompressSync';
            encodeMethod = 'brotliCompressSync';
            break;
        default:
            break;
    }
    let decodeBuffer: Buffer = oriBuffer;
    if (decodeMethod && encodeMethod) {
        decodeBuffer = zlib[decodeMethod](oriBuffer);
    }
    // 當JSON數據轉換錯的時候提示前端報錯
    let oriJSONRes: any;
    try {
        oriJSONRes = JSON.parse(decodeBuffer.toString());
    }
    catch (e) {
        console.error('[error]: JSON parse error! origin string: ', decodeBuffer.toString());
      // ErrorMessage爲自定義的消息格式,可以忽略ErrorMessage相關代碼
        oriJSONRes = new ErrorMessage({server: 'from node'}, 'Server Proxy data error');
    }
    const handledJSONRes = oriJSONRes instanceof ErrorMessage ? oriJSONRes : handleJsonResFunc(oriJSONRes);
    // 一定要轉成buffer,buffer長度和string長度不一樣
    const buffer = new Buffer(JSON.stringify(handledJSONRes));
    return decodeMethod && encodeMethod ? zlib[encodeMethod](buffer) : buffer;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章