├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── index.d.ts ├── index.js ├── package.json └── test ├── brotli.js ├── deflate.js ├── gzip.js └── uncompressed.js /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | node_modules/ 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 4 4 | - 5 5 | - 6 6 | - 7 7 | - 8 8 | - 10 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 XianFa Lang 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # node-http-proxy-json [![Build Status](https://travis-ci.org/langjt/node-http-proxy-json.svg?branch=master)](https://travis-ci.org/langjt/node-http-proxy-json) 2 | for [node-http-proxy](https://github.com/nodejitsu/node-http-proxy) transform the response json from the proxied server. 3 | 4 | ## Installation 5 | 6 | ``` 7 | npm install node-http-proxy-json 8 | ``` 9 | 10 | ## Motivation 11 | When using [node-http-proxy](https://github.com/nodejitsu/node-http-proxy) need to modify the response. If your proxy server returns HTML/XML document, you can try [Harmon](https://github.com/No9/harmon). 12 | But sometimes the proxy server only returns the JSON. For example, call API from the server. Usually the server will compress the data. 13 | So before using this repository, confirm your server compression format, currently only supports **gzip**、**deflate** and **uncompressed**. 14 | If you need other compression formats, please create a new Issue, and I will try to achieve it as much as possible. 15 | 16 | ## Use Cases 17 | 18 | #### Simulation server using gzip compression 19 | 20 | ```js 21 | var zlib = require('zlib'); 22 | var http = require('http'); 23 | var httpProxy = require('http-proxy'); 24 | var modifyResponse = require('node-http-proxy-json'); 25 | 26 | // Create a proxy server 27 | var proxy = httpProxy.createProxyServer({ 28 | target: 'http://localhost:5001' 29 | }); 30 | 31 | // Listen for the `proxyRes` event on `proxy`. 32 | proxy.on('proxyRes', function (proxyRes, req, res) { 33 | modifyResponse(res, proxyRes, function (body) { 34 | if (body) { 35 | // modify some information 36 | body.age = 2; 37 | delete body.version; 38 | } 39 | return body; // return value can be a promise 40 | }); 41 | }); 42 | 43 | // Create your server and then proxies the request 44 | var server = http.createServer(function (req, res) { 45 | proxy.web(req, res); 46 | }).listen(5000); 47 | 48 | // Create your target server 49 | var targetServer = http.createServer(function (req, res) { 50 | 51 | // Create gzipped content 52 | var gzip = zlib.Gzip(); 53 | var _write = res.write; 54 | var _end = res.end; 55 | 56 | gzip.on('data', function (buf) { 57 | _write.call(res, buf); 58 | }); 59 | gzip.on('end', function () { 60 | _end.call(res); 61 | }); 62 | 63 | res.write = function (data) { 64 | gzip.write(data); 65 | }; 66 | res.end = function () { 67 | gzip.end(); 68 | }; 69 | 70 | res.writeHead(200, {'Content-Type': 'application/json', 'Content-Encoding': 'gzip'}); 71 | res.write(JSON.stringify({name: 'node-http-proxy-json', age: 1, version: '1.0.0'})); 72 | res.end(); 73 | }).listen(5001); 74 | ``` 75 | 76 | #### Simulation server using deflate compression 77 | 78 | ```js 79 | var zlib = require('zlib'); 80 | var http = require('http'); 81 | var httpProxy = require('http-proxy'); 82 | var modifyResponse = require('../'); 83 | 84 | // Create a proxy server 85 | var proxy = httpProxy.createProxyServer({ 86 | target: 'http://localhost:5001' 87 | }); 88 | 89 | // Listen for the `proxyRes` event on `proxy`. 90 | proxy.on('proxyRes', function (proxyRes, req, res) { 91 | modifyResponse(res, proxyRes, function (body) { 92 | if (body) { 93 | // modify some information 94 | body.age = 2; 95 | delete body.version; 96 | } 97 | return body; // return value can be a promise 98 | }); 99 | }); 100 | 101 | // Create your server and then proxies the request 102 | var server = http.createServer(function (req, res) { 103 | proxy.web(req, res); 104 | }).listen(5000); 105 | 106 | // Create your target server 107 | var targetServer = http.createServer(function (req, res) { 108 | 109 | // Create deflated content 110 | var deflate = zlib.Deflate(); 111 | var _write = res.write; 112 | var _end = res.end; 113 | 114 | deflate.on('data', function (buf) { 115 | _write.call(res, buf); 116 | }); 117 | deflate.on('end', function () { 118 | _end.call(res); 119 | }); 120 | 121 | res.write = function (data) { 122 | deflate.write(data); 123 | }; 124 | res.end = function () { 125 | deflate.end(); 126 | }; 127 | 128 | res.writeHead(200, {'Content-Type': 'application/json', 'Content-Encoding': 'deflate'}); 129 | res.write(JSON.stringify({name: 'node-http-proxy-json', age: 1, version: '1.0.0'})); 130 | res.end(); 131 | }).listen(5001); 132 | ``` 133 | 134 | #### Server does not enable compression 135 | 136 | ```js 137 | var http = require('http'); 138 | var httpProxy = require('http-proxy'); 139 | var modifyResponse = require('../'); 140 | 141 | // Create a proxy server 142 | var proxy = httpProxy.createProxyServer({ 143 | target: 'http://localhost:5001' 144 | }); 145 | 146 | // Listen for the `proxyRes` event on `proxy`. 147 | proxy.on('proxyRes', function (proxyRes, req, res) { 148 | modifyResponse(res, proxyRes, function (body) { 149 | if (body) { 150 | // modify some information 151 | body.age = 2; 152 | delete body.version; 153 | } 154 | return body; // return value can be a promise 155 | }); 156 | }); 157 | 158 | // Create your server and then proxies the request 159 | var server = http.createServer(function (req, res) { 160 | proxy.web(req, res); 161 | }).listen(5000); 162 | 163 | // Create your target server 164 | var targetServer = http.createServer(function (req, res) { 165 | res.writeHead(200, {'Content-Type': 'application/json', 'Content-Encoding': 'deflate'}); 166 | res.write(JSON.stringify({name: 'node-http-proxy-json', age: 1, version: '1.0.0'})); 167 | res.end(); 168 | }).listen(5001); 169 | ``` 170 | 171 | ## Tests 172 | 173 | To run the test suite, first install the dependencies, then run `npm test`: 174 | 175 | ```bash 176 | $ npm install 177 | $ npm test 178 | ``` 179 | 180 | ## License 181 | 182 | [MIT](http://opensource.org/licenses/MIT) 183 | -------------------------------------------------------------------------------- /index.d.ts: -------------------------------------------------------------------------------- 1 | import {ServerResponse, IncomingMessage} from "http" 2 | 3 | declare module 'node-http-proxy-json' { 4 | /** 5 | * Modify the response of json 6 | * @param res {Response} The http response 7 | * @param proxyRes {proxyRes|String} String: The http header content-encoding: gzip/deflate 8 | * @param callback {Function} Custom modified logic 9 | */ 10 | export default function modifyResponse ( 11 | res: ServerResponse, 12 | proxyRes: IncomingMessage | String | undefined, 13 | callback: (body: any) => any 14 | ): null 15 | } 16 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const zlib = require('zlib'); 4 | const concatStream = require('concat-stream'); 5 | const BufferHelper = require('bufferhelper'); 6 | const isString = function (obj) { 7 | return Object.prototype.toString.call(obj) === '[object String]'; 8 | } 9 | 10 | /** 11 | * Modify the response of json 12 | * @param res {Response} The http response 13 | * @param proxyRes {proxyRes|String} String: The http header content-encoding: gzip/deflate 14 | * @param callback {Function} Custom modified logic 15 | */ 16 | module.exports = function modifyResponse(res, proxyRes, callback) { 17 | let contentEncoding = proxyRes; 18 | if (proxyRes && proxyRes.headers) { 19 | contentEncoding = proxyRes.headers['content-encoding']; 20 | // Delete the content-length if it exists. Otherwise, an exception will occur 21 | // @see: https://github.com/langjt/node-http-proxy-json/issues/10 22 | if ('content-length' in proxyRes.headers) { 23 | delete proxyRes.headers['content-length']; 24 | } 25 | } 26 | 27 | let unzip, zip; 28 | // Now only deal with the gzip/deflate/brotli/undefined content-encoding. 29 | switch (contentEncoding) { 30 | case 'gzip': 31 | unzip = zlib.Gunzip(); 32 | zip = zlib.Gzip(); 33 | break; 34 | case 'deflate': 35 | unzip = zlib.Inflate(); 36 | zip = zlib.Deflate(); 37 | break; 38 | case 'br': 39 | unzip = zlib.BrotliDecompress && zlib.BrotliDecompress(); 40 | zip = zlib.BrotliCompress && zlib.BrotliCompress(); 41 | break; 42 | } 43 | 44 | // The cache response method can be called after the modification. 45 | let _write = res.write; 46 | let _end = res.end; 47 | 48 | if (unzip) { 49 | unzip.on('error', function (e) { 50 | console.log('Unzip error: ', e); 51 | _end.call(res); 52 | }); 53 | handleCompressed(res, _write, _end, unzip, zip, callback); 54 | } else if (!contentEncoding) { 55 | handleUncompressed(res, _write, _end, callback); 56 | } else { 57 | console.log('Not supported content-encoding: ' + contentEncoding); 58 | } 59 | }; 60 | 61 | /** 62 | * handle compressed 63 | */ 64 | function handleCompressed(res, _write, _end, unzip, zip, callback) { 65 | // The rewrite response method is replaced by unzip stream. 66 | res.write = data => { unzip.write(data) }; 67 | 68 | res.end = () => unzip.end(); 69 | 70 | // Concat the unzip stream. 71 | let concatWrite = concatStream(data => { 72 | let body; 73 | try { 74 | body = JSON.parse(data.toString()); 75 | } catch (e) { 76 | body = data.toString(); 77 | } 78 | 79 | // Custom modified logic 80 | if (typeof callback === 'function') { 81 | body = callback(body); 82 | } 83 | 84 | let finish = _body => { 85 | // empty response body 86 | if (!_body) { 87 | _body = ''; 88 | } 89 | // Converts the JSON to buffer. 90 | let body = new Buffer(isString(_body) ? _body : JSON.stringify(_body)); 91 | 92 | // Call the response method and recover the content-encoding. 93 | zip.on('data', chunk => _write.call(res, chunk)); 94 | zip.on('end', () => _end.call(res)); 95 | 96 | zip.write(body); 97 | zip.end(); 98 | }; 99 | 100 | if (body && body.then) { 101 | body.then(finish); 102 | } else { 103 | finish(body); 104 | } 105 | }); 106 | 107 | unzip.pipe(concatWrite); 108 | } 109 | 110 | /** 111 | * handle Uncompressed 112 | */ 113 | function handleUncompressed(res, _write, _end, callback) { 114 | let buffer = new BufferHelper(); 115 | // Rewrite response method and get the content. 116 | res.write = data => buffer.concat(data); 117 | 118 | res.end = () => { 119 | let body; 120 | try { 121 | body = JSON.parse(buffer.toBuffer().toString()); 122 | } catch (e) { 123 | body = buffer.toBuffer().toString(); 124 | } 125 | 126 | // Custom modified logic 127 | if (typeof callback === 'function') { 128 | body = callback(body); 129 | } 130 | 131 | let finish = _body => { 132 | // empty response body 133 | if (!_body) { 134 | _body = ''; 135 | } 136 | // Converts the JSON to buffer. 137 | let body = new Buffer(isString(_body) ? _body : JSON.stringify(_body)); 138 | 139 | // Call the response method 140 | _write.call(res, body); 141 | _end.call(res); 142 | }; 143 | 144 | if (body && body.then) { 145 | body.then(finish); 146 | } else { 147 | finish(body); 148 | } 149 | }; 150 | } 151 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-http-proxy-json", 3 | "version": "0.1.9", 4 | "description": "for node-http-proxy transform the response json from the proxied server.", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "./node_modules/.bin/mocha -R spec ./test/*.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git+https://github.com/langjt/node-http-proxy-json.git" 12 | }, 13 | "keywords": [ 14 | "http-proxy", 15 | "streaming", 16 | "json" 17 | ], 18 | "author": "XianFa Lang (http://www.cnblogs.com/langjt)", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/langjt/node-http-proxy-json/issues" 22 | }, 23 | "homepage": "https://github.com/langjt/node-http-proxy-json#readme", 24 | "dependencies": { 25 | "bufferhelper": "^0.2.1", 26 | "concat-stream": "^1.5.1" 27 | }, 28 | "devDependencies": { 29 | "chai": "^3.5.0", 30 | "http-proxy": "^1.13.3", 31 | "mocha": "^2.5.3" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /test/brotli.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Test content-encoding for brotli 4 | */ 5 | 6 | const assert = require('chai').assert; 7 | 8 | const zlib = require('zlib'); 9 | const http = require('http'); 10 | const httpProxy = require('http-proxy'); 11 | const modifyResponse = require('../'); 12 | 13 | const SERVER_PORT = 5000; 14 | const TARGET_SERVER_PORT = 5001; 15 | 16 | const isObject = function (obj) { 17 | return Object.prototype.toString.call(obj) === '[object Object]'; 18 | } 19 | 20 | describe('modifyResponse--brotli', function() { 21 | if (typeof zlib.createBrotliCompress !== 'function') { 22 | return console.log('Brotli not available. Skipping "modifyResponse--brotli" test.'); 23 | } 24 | 25 | let proxy, server, targetServer; 26 | beforeEach(() => { 27 | // Create a proxy server 28 | proxy = httpProxy.createProxyServer({ 29 | target: 'http://localhost:' + TARGET_SERVER_PORT, 30 | }); 31 | 32 | // Create your server and then proxies the request 33 | server = http 34 | .createServer((req, res) => { 35 | proxy.web(req, res); 36 | }) 37 | .listen(SERVER_PORT); 38 | 39 | // Create your target server 40 | targetServer = http 41 | .createServer((req, res) => { 42 | // Create compressed content 43 | let compressed = zlib.createBrotliCompress(); 44 | let _write = res.write; 45 | let _end = res.end; 46 | 47 | compressed.on('data', buf => _write.call(res, buf)); 48 | compressed.on('end', () => _end.call(res)); 49 | 50 | res.write = data => compressed.write(data); 51 | res.end = () => compressed.end(); 52 | 53 | res.writeHead(200, { 54 | 'Content-Type': 'application/json', 55 | 'Content-Encoding': 'br', 56 | }); 57 | 58 | res.write( 59 | JSON.stringify({ 60 | name: 'node-http-proxy-json', 61 | age: 1, 62 | version: '1.0.0', 63 | }) 64 | ); 65 | res.end(); 66 | }) 67 | .listen(TARGET_SERVER_PORT); 68 | }); 69 | 70 | afterEach(() => { 71 | proxy.close(); 72 | server.close(); 73 | targetServer.close(); 74 | }); 75 | 76 | describe('callback returns data', () => { 77 | beforeEach(() => { 78 | // Listen for the `proxyRes` event on `proxy`. 79 | proxy.on('proxyRes', (proxyRes, req, res) => { 80 | modifyResponse(res, proxyRes, body => { 81 | if (isObject(body)) { 82 | // modify some information 83 | body.age = 2; 84 | delete body.version; 85 | } 86 | return body; 87 | }); 88 | }); 89 | }); 90 | 91 | it('brotli: modify response json successfully', done => { 92 | // Test server 93 | http.get('http://localhost:' + SERVER_PORT, res => { 94 | let body = ''; 95 | let decompressed = zlib.createBrotliDecompress(); 96 | res.pipe(decompressed); 97 | 98 | decompressed 99 | .on('data', chunk => { 100 | body += chunk; 101 | }) 102 | .on('end', () => { 103 | assert.equal( 104 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 105 | body 106 | ); 107 | 108 | done(); 109 | }); 110 | }); 111 | }); 112 | }); 113 | 114 | describe('callback returns a promise', () => { 115 | beforeEach(() => { 116 | // Listen for the `proxyRes` event on `proxy`. 117 | proxy.on('proxyRes', (proxyRes, req, res) => { 118 | modifyResponse(res, proxyRes, body => { 119 | if (isObject(body)) { 120 | // modify some information 121 | body.age = 2; 122 | delete body.version; 123 | } 124 | return Promise.resolve(body); 125 | }); 126 | }); 127 | }); 128 | 129 | it('brotli: modify response json successfully', done => { 130 | // Test server 131 | http.get('http://localhost:' + SERVER_PORT, res => { 132 | let body = ''; 133 | let decompressed = zlib.createBrotliDecompress(); 134 | res.pipe(decompressed); 135 | 136 | decompressed 137 | .on('data', chunk => { 138 | body += chunk; 139 | }) 140 | .on('end', () => { 141 | assert.equal( 142 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 143 | body 144 | ); 145 | 146 | done(); 147 | }); 148 | }); 149 | }); 150 | }); 151 | }); 152 | 153 | -------------------------------------------------------------------------------- /test/deflate.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Test content-encoding for deflate 4 | */ 5 | 6 | const assert = require('chai').assert; 7 | 8 | const zlib = require('zlib'); 9 | const http = require('http'); 10 | const httpProxy = require('http-proxy'); 11 | const modifyResponse = require('../'); 12 | 13 | const SERVER_PORT = 5002; 14 | const TARGET_SERVER_PORT = 5003; 15 | 16 | const isObject = function (obj) { 17 | return Object.prototype.toString.call(obj) === '[object Object]'; 18 | } 19 | 20 | describe('modifyResponse--deflate', () => { 21 | let proxy, server, targetServer; 22 | beforeEach(() => { 23 | // Create a proxy server 24 | proxy = httpProxy.createProxyServer({ 25 | target: 'http://localhost:' + TARGET_SERVER_PORT, 26 | }); 27 | 28 | // Create your server and then proxies the request 29 | server = http 30 | .createServer((req, res) => proxy.web(req, res)) 31 | .listen(SERVER_PORT); 32 | 33 | // Create your target server 34 | targetServer = http 35 | .createServer(function (req, res) { 36 | // Create deflated content 37 | let deflate = zlib.Deflate(); 38 | let _write = res.write; 39 | let _end = res.end; 40 | 41 | deflate.on('data', buf => _write.call(res, buf)); 42 | deflate.on('end', () => _end.call(res)); 43 | 44 | res.write = data => deflate.write(data); 45 | res.end = () => deflate.end(); 46 | 47 | res.writeHead(200, { 48 | 'Content-Type': 'application/json', 49 | 'Content-Encoding': 'deflate', 50 | }); 51 | 52 | res.write( 53 | JSON.stringify({ 54 | name: 'node-http-proxy-json', 55 | age: 1, 56 | version: '1.0.0', 57 | }) 58 | ); 59 | 60 | res.end(); 61 | }) 62 | .listen(TARGET_SERVER_PORT); 63 | }); 64 | 65 | afterEach(() => { 66 | proxy.close(); 67 | server.close(); 68 | targetServer.close(); 69 | }); 70 | 71 | describe('callback returns data', () => { 72 | beforeEach(() => { 73 | // Listen for the `proxyRes` event on `proxy`. 74 | proxy.on('proxyRes', (proxyRes, req, res) => { 75 | modifyResponse(res, proxyRes, body => { 76 | if (isObject(body)) { 77 | // modify some information 78 | body.age = 2; 79 | delete body.version; 80 | } 81 | return body; 82 | }); 83 | }); 84 | }); 85 | it('deflate: modify response json successfully', done => { 86 | // Test server 87 | http.get('http://localhost:' + SERVER_PORT, res => { 88 | let body = ''; 89 | let inflate = zlib.Inflate(); 90 | res.pipe(inflate); 91 | 92 | inflate 93 | .on('data', function (chunk) { 94 | body += chunk; 95 | }) 96 | .on('end', function () { 97 | assert.equal( 98 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 99 | body 100 | ); 101 | 102 | done(); 103 | }); 104 | }); 105 | }); 106 | }); 107 | 108 | describe('callback returns a promise', () => { 109 | beforeEach(() => { 110 | // Listen for the `proxyRes` event on `proxy`. 111 | proxy.on('proxyRes', (proxyRes, req, res) => { 112 | modifyResponse(res, proxyRes, body => { 113 | if (isObject(body)) { 114 | // modify some information 115 | body.age = 2; 116 | delete body.version; 117 | } 118 | return Promise.resolve(body); 119 | }); 120 | }); 121 | }); 122 | it('deflate: modify response json successfully', done => { 123 | // Test server 124 | http.get('http://localhost:' + SERVER_PORT, res => { 125 | let body = ''; 126 | let inflate = zlib.Inflate(); 127 | res.pipe(inflate); 128 | 129 | inflate 130 | .on('data', function (chunk) { 131 | body += chunk; 132 | }) 133 | .on('end', function () { 134 | assert.equal( 135 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 136 | body 137 | ); 138 | 139 | done(); 140 | }); 141 | }); 142 | }); 143 | }); 144 | }); 145 | -------------------------------------------------------------------------------- /test/gzip.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | /** 3 | * Test content-encoding for gzip 4 | */ 5 | 6 | const assert = require('chai').assert; 7 | 8 | const zlib = require('zlib'); 9 | const http = require('http'); 10 | const httpProxy = require('http-proxy'); 11 | const modifyResponse = require('../'); 12 | 13 | const SERVER_PORT = 5000; 14 | const TARGET_SERVER_PORT = 5001; 15 | const isObject = function (obj) { 16 | return Object.prototype.toString.call(obj) === '[object Object]'; 17 | } 18 | 19 | describe('modifyResponse--gzip', function () { 20 | let proxy, server, targetServer; 21 | beforeEach(() => { 22 | // Create a proxy server 23 | proxy = httpProxy.createProxyServer({ 24 | target: 'http://localhost:' + TARGET_SERVER_PORT, 25 | }); 26 | 27 | // Create your server and then proxies the request 28 | server = http 29 | .createServer((req, res) => { 30 | proxy.web(req, res); 31 | }) 32 | .listen(SERVER_PORT); 33 | 34 | // Create your target server 35 | targetServer = http 36 | .createServer((req, res) => { 37 | // Create gzipped content 38 | let gzip = zlib.Gzip(); 39 | let _write = res.write; 40 | let _end = res.end; 41 | 42 | gzip.on('data', buf => _write.call(res, buf)); 43 | gzip.on('end', () => _end.call(res)); 44 | 45 | res.write = data => gzip.write(data); 46 | res.end = () => gzip.end(); 47 | 48 | res.writeHead(200, { 49 | 'Content-Type': 'application/json', 50 | 'Content-Encoding': 'gzip', 51 | }); 52 | 53 | res.write( 54 | JSON.stringify({ 55 | name: 'node-http-proxy-json', 56 | age: 1, 57 | version: '1.0.0', 58 | }) 59 | ); 60 | res.end(); 61 | }) 62 | .listen(TARGET_SERVER_PORT); 63 | }); 64 | 65 | afterEach(() => { 66 | proxy.close(); 67 | server.close(); 68 | targetServer.close(); 69 | }); 70 | 71 | describe('callback returns data', () => { 72 | beforeEach(() => { 73 | // Listen for the `proxyRes` event on `proxy`. 74 | proxy.on('proxyRes', (proxyRes, req, res) => { 75 | modifyResponse(res, proxyRes, body => { 76 | if (isObject(body)) { 77 | // modify some information 78 | body.age = 2; 79 | delete body.version; 80 | } 81 | return body; 82 | }); 83 | }); 84 | }); 85 | 86 | it('gzip: modify response json successfully', done => { 87 | // Test server 88 | http.get('http://localhost:' + SERVER_PORT, res => { 89 | let body = ''; 90 | let gunzip = zlib.Gunzip(); 91 | res.pipe(gunzip); 92 | 93 | gunzip 94 | .on('data', chunk => { 95 | body += chunk; 96 | }) 97 | .on('end', () => { 98 | assert.equal( 99 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 100 | body 101 | ); 102 | 103 | done(); 104 | }); 105 | }); 106 | }); 107 | }); 108 | 109 | describe('callback returns a promise', () => { 110 | beforeEach(() => { 111 | // Listen for the `proxyRes` event on `proxy`. 112 | proxy.on('proxyRes', (proxyRes, req, res) => { 113 | modifyResponse(res, proxyRes, body => { 114 | if (isObject(body)) { 115 | // modify some information 116 | body.age = 2; 117 | delete body.version; 118 | } 119 | return Promise.resolve(body); 120 | }); 121 | }); 122 | }); 123 | 124 | it('gzip: modify response json successfully', done => { 125 | // Test server 126 | http.get('http://localhost:' + SERVER_PORT, res => { 127 | let body = ''; 128 | let gunzip = zlib.Gunzip(); 129 | res.pipe(gunzip); 130 | 131 | gunzip 132 | .on('data', chunk => { 133 | body += chunk; 134 | }) 135 | .on('end', () => { 136 | assert.equal( 137 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 138 | body 139 | ); 140 | 141 | done(); 142 | }); 143 | }); 144 | }); 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /test/uncompressed.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | /** 4 | * Test content-encoding for uncompressed 5 | */ 6 | 7 | const assert = require('chai').assert; 8 | 9 | const http = require('http'); 10 | const httpProxy = require('http-proxy'); 11 | const modifyResponse = require('../'); 12 | 13 | const SERVER_PORT = 5004; 14 | const TARGET_SERVER_PORT = 5005; 15 | const isObject = function (obj) { 16 | return Object.prototype.toString.call(obj) === '[object Object]'; 17 | } 18 | 19 | describe('modifyResponse--uncompressed', function () { 20 | let proxy, server, targetServer; 21 | beforeEach(() => { 22 | // Create a proxy server 23 | proxy = httpProxy.createProxyServer({ 24 | target: 'http://localhost:' + TARGET_SERVER_PORT, 25 | }); 26 | 27 | // Create your server and then proxies the request 28 | server = http 29 | .createServer((req, res) => proxy.web(req, res)) 30 | .listen(SERVER_PORT); 31 | 32 | // Create your target server 33 | targetServer = http 34 | .createServer((req, res) => { 35 | res.writeHead(200, { 'Content-Type': 'application/json' }); 36 | res.write( 37 | JSON.stringify({ 38 | name: 'node-http-proxy-json', 39 | age: 1, 40 | version: '1.0.0', 41 | }) 42 | ); 43 | res.end(); 44 | }) 45 | .listen(TARGET_SERVER_PORT); 46 | }); 47 | 48 | afterEach(() => { 49 | proxy.close(); 50 | server.close(); 51 | targetServer.close(); 52 | }); 53 | 54 | describe('callback returns data', () => { 55 | beforeEach(() => { 56 | // Listen for the `proxyRes` event on `proxy`. 57 | proxy.on('proxyRes', function (proxyRes, req, res) { 58 | modifyResponse(res, proxyRes, body => { 59 | if (isObject(body)) { 60 | // modify some information 61 | body.age = 2; 62 | delete body.version; 63 | } 64 | return body; 65 | }); 66 | }); 67 | }); 68 | 69 | it('uncompressed: modify response json successfully', done => { 70 | // Test server 71 | http.get('http://localhost:' + SERVER_PORT, res => { 72 | let body = ''; 73 | res.on('data', chunk => (body += chunk)).on('end', () => { 74 | assert.equal( 75 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 76 | body 77 | ); 78 | done(); 79 | }); 80 | }); 81 | }); 82 | }); 83 | 84 | describe('callback returns a promise', () => { 85 | beforeEach(() => { 86 | // Listen for the `proxyRes` event on `proxy`. 87 | proxy.on('proxyRes', (proxyRes, req, res) => { 88 | modifyResponse(res, proxyRes, body => { 89 | if (isObject(body)) { 90 | // modify some information 91 | body.age = 2; 92 | delete body.version; 93 | } 94 | return Promise.resolve(body); 95 | }); 96 | }); 97 | }); 98 | 99 | it('uncompressed: modify response json successfully', done => { 100 | // Test server 101 | http.get('http://localhost:' + SERVER_PORT, res => { 102 | let body = ''; 103 | res.on('data', chunk => (body += chunk)).on('end', () => { 104 | assert.equal( 105 | JSON.stringify({ name: 'node-http-proxy-json', age: 2 }), 106 | body 107 | ); 108 | 109 | done(); 110 | }); 111 | }); 112 | }); 113 | }); 114 | }); 115 | --------------------------------------------------------------------------------