node-http-proxy-json
Version:
for node-http-proxy transform the response json from the proxied server.
151 lines (130 loc) • 3.87 kB
JavaScript
;
const zlib = require('zlib');
const concatStream = require('concat-stream');
const BufferHelper = require('bufferhelper');
const isString = function (obj) {
return Object.prototype.toString.call(obj) === '[object String]';
}
/**
* Modify the response of json
* @param res {Response} The http response
* @param proxyRes {proxyRes|String} String: The http header content-encoding: gzip/deflate
* @param callback {Function} Custom modified logic
*/
module.exports = function modifyResponse(res, proxyRes, callback) {
let contentEncoding = proxyRes;
if (proxyRes && proxyRes.headers) {
contentEncoding = proxyRes.headers['content-encoding'];
// Delete the content-length if it exists. Otherwise, an exception will occur
// @see: https://github.com/langjt/node-http-proxy-json/issues/10
if ('content-length' in proxyRes.headers) {
delete proxyRes.headers['content-length'];
}
}
let unzip, zip;
// Now only deal with the gzip/deflate/undefined content-encoding.
switch (contentEncoding) {
case 'gzip':
unzip = zlib.Gunzip();
zip = zlib.Gzip();
break;
case 'deflate':
unzip = zlib.Inflate();
zip = zlib.Deflate();
break;
case 'br':
unzip = zlib.BrotliDecompress && zlib.BrotliDecompress();
zip = zlib.BrotliCompress && zlib.BrotliCompress();
break;
}
// The cache response method can be called after the modification.
let _write = res.write;
let _end = res.end;
if (unzip) {
unzip.on('error', function (e) {
console.log('Unzip error: ', e);
_end.call(res);
});
handleCompressed(res, _write, _end, unzip, zip, callback);
} else if (!contentEncoding) {
handleUncompressed(res, _write, _end, callback);
} else {
console.log('Not supported content-encoding: ' + contentEncoding);
}
};
/**
* handle compressed
*/
function handleCompressed(res, _write, _end, unzip, zip, callback) {
// The rewrite response method is replaced by unzip stream.
res.write = data => { unzip.write(data) };
res.end = () => unzip.end();
// Concat the unzip stream.
let concatWrite = concatStream(data => {
let body;
try {
body = JSON.parse(data.toString());
} catch (e) {
body = data.toString();
}
// Custom modified logic
if (typeof callback === 'function') {
body = callback(body);
}
let finish = _body => {
// empty response body
if (!_body) {
_body = '';
}
// Converts the JSON to buffer.
let body = new Buffer(isString(_body) ? _body : JSON.stringify(_body));
// Call the response method and recover the content-encoding.
zip.on('data', chunk => _write.call(res, chunk));
zip.on('end', () => _end.call(res));
zip.write(body);
zip.end();
};
if (body && body.then) {
body.then(finish);
} else {
finish(body);
}
});
unzip.pipe(concatWrite);
}
/**
* handle Uncompressed
*/
function handleUncompressed(res, _write, _end, callback) {
let buffer = new BufferHelper();
// Rewrite response method and get the content.
res.write = data => buffer.concat(data);
res.end = () => {
let body;
try {
body = JSON.parse(buffer.toBuffer().toString());
} catch (e) {
body = buffer.toBuffer().toString();
}
// Custom modified logic
if (typeof callback === 'function') {
body = callback(body);
}
let finish = _body => {
// empty response body
if (!_body) {
_body = '';
}
// Converts the JSON to buffer.
let body = new Buffer(isString(_body) ? _body : JSON.stringify(_body));
// Call the response method
_write.call(res, body);
_end.call(res);
};
if (body && body.then) {
body.then(finish);
} else {
finish(body);
}
};
}