UNPKG

19.4 kBMarkdownView Raw
1<p align="center">
2 <img src="https://raw.github.com/http-party/node-http-proxy/master/doc/logo.png"/>
3</p>
4
5# node-http-proxy [![Build Status](https://travis-ci.org/http-party/node-http-proxy.svg?branch=master)](https://travis-ci.org/http-party/node-http-proxy) [![codecov](https://codecov.io/gh/http-party/node-http-proxy/branch/master/graph/badge.svg)](https://codecov.io/gh/http-party/node-http-proxy)
6
7`node-http-proxy` is an HTTP programmable proxying library that supports
8websockets. It is suitable for implementing components such as reverse
9proxies and load balancers.
10
11### Table of Contents
12 * [Installation](#installation)
13 * [Upgrading from 0.8.x ?](#upgrading-from-08x-)
14 * [Core Concept](#core-concept)
15 * [Use Cases](#use-cases)
16 * [Setup a basic stand-alone proxy server](#setup-a-basic-stand-alone-proxy-server)
17 * [Setup a stand-alone proxy server with custom server logic](#setup-a-stand-alone-proxy-server-with-custom-server-logic)
18 * [Setup a stand-alone proxy server with proxy request header re-writing](#setup-a-stand-alone-proxy-server-with-proxy-request-header-re-writing)
19 * [Modify a response from a proxied server](#modify-a-response-from-a-proxied-server)
20 * [Setup a stand-alone proxy server with latency](#setup-a-stand-alone-proxy-server-with-latency)
21 * [Using HTTPS](#using-https)
22 * [Proxying WebSockets](#proxying-websockets)
23 * [Options](#options)
24 * [Listening for proxy events](#listening-for-proxy-events)
25 * [Shutdown](#shutdown)
26 * [Miscellaneous](#miscellaneous)
27 * [Test](#test)
28 * [ProxyTable API](#proxytable-api)
29 * [Logo](#logo)
30 * [Contributing and Issues](#contributing-and-issues)
31 * [License](#license)
32
33### Installation
34
35`npm install http-proxy --save`
36
37**[Back to top](#table-of-contents)**
38
39### Upgrading from 0.8.x ?
40
41Click [here](UPGRADING.md)
42
43**[Back to top](#table-of-contents)**
44
45### Core Concept
46
47A new proxy is created by calling `createProxyServer` and passing
48an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L26-L42))
49
50```javascript
51var httpProxy = require('http-proxy');
52
53var proxy = httpProxy.createProxyServer(options); // See (†)
54```
55†Unless listen(..) is invoked on the object, this does not create a webserver. See below.
56
57An object will be returned with four methods:
58
59* web `req, res, [options]` (used for proxying regular HTTP(S) requests)
60* ws `req, socket, head, [options]` (used for proxying WS(S) requests)
61* listen `port` (a function that wraps the object in a webserver, for your convenience)
62* close `[callback]` (a function that closes the inner webserver and stops listening on given port)
63
64It is then possible to proxy requests by calling these functions
65
66```javascript
67http.createServer(function(req, res) {
68 proxy.web(req, res, { target: 'http://mytarget.com:8080' });
69});
70```
71
72Errors can be listened on either using the Event Emitter API
73
74```javascript
75proxy.on('error', function(e) {
76 ...
77});
78```
79
80or using the callback API
81
82```javascript
83proxy.web(req, res, { target: 'http://mytarget.com:8080' }, function(e) { ... });
84```
85
86When a request is proxied it follows two different pipelines ([available here](lib/http-proxy/passes))
87which apply transformations to both the `req` and `res` object.
88The first pipeline (incoming) is responsible for the creation and manipulation of the stream that connects your client to the target.
89The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data
90to the client.
91
92**[Back to top](#table-of-contents)**
93
94### Use Cases
95
96#### Setup a basic stand-alone proxy server
97
98```js
99var http = require('http'),
100 httpProxy = require('http-proxy');
101//
102// Create your proxy server and set the target in the options.
103//
104httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000); // See (†)
105
106//
107// Create your target server
108//
109http.createServer(function (req, res) {
110 res.writeHead(200, { 'Content-Type': 'text/plain' });
111 res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
112 res.end();
113}).listen(9000);
114```
115†Invoking listen(..) triggers the creation of a web server. Otherwise, just the proxy instance is created.
116
117**[Back to top](#table-of-contents)**
118
119#### Setup a stand-alone proxy server with custom server logic
120This example shows how you can proxy a request using your own HTTP server
121and also you can put your own logic to handle the request.
122
123```js
124var http = require('http'),
125 httpProxy = require('http-proxy');
126
127//
128// Create a proxy server with custom application logic
129//
130var proxy = httpProxy.createProxyServer({});
131
132//
133// Create your custom server and just call `proxy.web()` to proxy
134// a web request to the target passed in the options
135// also you can use `proxy.ws()` to proxy a websockets request
136//
137var server = http.createServer(function(req, res) {
138 // You can define here your custom logic to handle the request
139 // and then proxy the request.
140 proxy.web(req, res, { target: 'http://127.0.0.1:5050' });
141});
142
143console.log("listening on port 5050")
144server.listen(5050);
145```
146
147**[Back to top](#table-of-contents)**
148
149#### Setup a stand-alone proxy server with proxy request header re-writing
150This example shows how you can proxy a request using your own HTTP server that
151modifies the outgoing proxy request by adding a special header.
152
153```js
154var http = require('http'),
155 httpProxy = require('http-proxy');
156
157//
158// Create a proxy server with custom application logic
159//
160var proxy = httpProxy.createProxyServer({});
161
162// To modify the proxy connection before data is sent, you can listen
163// for the 'proxyReq' event. When the event is fired, you will receive
164// the following arguments:
165// (http.ClientRequest proxyReq, http.IncomingMessage req,
166// http.ServerResponse res, Object options). This mechanism is useful when
167// you need to modify the proxy request before the proxy connection
168// is made to the target.
169//
170proxy.on('proxyReq', function(proxyReq, req, res, options) {
171 proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
172});
173
174var server = http.createServer(function(req, res) {
175 // You can define here your custom logic to handle the request
176 // and then proxy the request.
177 proxy.web(req, res, {
178 target: 'http://127.0.0.1:5050'
179 });
180});
181
182console.log("listening on port 5050")
183server.listen(5050);
184```
185
186**[Back to top](#table-of-contents)**
187
188#### Modify a response from a proxied server
189Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on.
190
191[Harmon](https://github.com/No9/harmon) allows you to do this in a streaming style so as to keep the pressure on the proxy to a minimum.
192
193**[Back to top](#table-of-contents)**
194
195#### Setup a stand-alone proxy server with latency
196
197```js
198var http = require('http'),
199 httpProxy = require('http-proxy');
200
201//
202// Create a proxy server with latency
203//
204var proxy = httpProxy.createProxyServer();
205
206//
207// Create your server that makes an operation that waits a while
208// and then proxies the request
209//
210http.createServer(function (req, res) {
211 // This simulates an operation that takes 500ms to execute
212 setTimeout(function () {
213 proxy.web(req, res, {
214 target: 'http://localhost:9008'
215 });
216 }, 500);
217}).listen(8008);
218
219//
220// Create your target server
221//
222http.createServer(function (req, res) {
223 res.writeHead(200, { 'Content-Type': 'text/plain' });
224 res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
225 res.end();
226}).listen(9008);
227```
228
229**[Back to top](#table-of-contents)**
230
231#### Using HTTPS
232You can activate the validation of a secure SSL certificate to the target connection (avoid self-signed certs), just set `secure: true` in the options.
233
234##### HTTPS -> HTTP
235
236```js
237//
238// Create the HTTPS proxy server in front of a HTTP server
239//
240httpProxy.createServer({
241 target: {
242 host: 'localhost',
243 port: 9009
244 },
245 ssl: {
246 key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
247 cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
248 }
249}).listen(8009);
250```
251
252##### HTTPS -> HTTPS
253
254```js
255//
256// Create the proxy server listening on port 443
257//
258httpProxy.createServer({
259 ssl: {
260 key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
261 cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
262 },
263 target: 'https://localhost:9010',
264 secure: true // Depends on your needs, could be false.
265}).listen(443);
266```
267
268##### HTTP -> HTTPS (using a PKCS12 client certificate)
269
270```js
271//
272// Create an HTTP proxy server with an HTTPS target
273//
274httpProxy.createProxyServer({
275 target: {
276 protocol: 'https:',
277 host: 'my-domain-name',
278 port: 443,
279 pfx: fs.readFileSync('path/to/certificate.p12'),
280 passphrase: 'password',
281 },
282 changeOrigin: true,
283}).listen(8000);
284```
285
286**[Back to top](#table-of-contents)**
287
288#### Proxying WebSockets
289You can activate the websocket support for the proxy using `ws:true` in the options.
290
291```js
292//
293// Create a proxy server for websockets
294//
295httpProxy.createServer({
296 target: 'ws://localhost:9014',
297 ws: true
298}).listen(8014);
299```
300
301Also you can proxy the websocket requests just calling the `ws(req, socket, head)` method.
302
303```js
304//
305// Setup our server to proxy standard HTTP requests
306//
307var proxy = new httpProxy.createProxyServer({
308 target: {
309 host: 'localhost',
310 port: 9015
311 }
312});
313var proxyServer = http.createServer(function (req, res) {
314 proxy.web(req, res);
315});
316
317//
318// Listen to the `upgrade` event and proxy the
319// WebSocket requests as well.
320//
321proxyServer.on('upgrade', function (req, socket, head) {
322 proxy.ws(req, socket, head);
323});
324
325proxyServer.listen(8015);
326```
327
328**[Back to top](#table-of-contents)**
329
330### Options
331
332`httpProxy.createProxyServer` supports the following options:
333
334* **target**: url string to be parsed with the url module
335* **forward**: url string to be parsed with the url module
336* **agent**: object to be passed to http(s).request (see Node's [https agent](http://nodejs.org/api/https.html#https_class_https_agent) and [http agent](http://nodejs.org/api/http.html#http_class_http_agent) objects)
337* **ssl**: object to be passed to https.createServer()
338* **ws**: true/false, if you want to proxy websockets
339* **xfwd**: true/false, adds x-forward headers
340* **secure**: true/false, if you want to verify the SSL Certs
341* **toProxy**: true/false, passes the absolute URL as the `path` (useful for proxying to proxies)
342* **prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
343* **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).
344* **localAddress**: Local interface string to bind for outgoing connections
345* **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL
346* **preserveHeaderKeyCase**: true/false, Default: false - specify whether you want to keep letter case of response header key
347* **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header.
348* **hostRewrite**: rewrites the location hostname on (201/301/302/307/308) redirects.
349* **autoRewrite**: rewrites the location host/port on (201/301/302/307/308) redirects based on requested host/port. Default: false.
350* **protocolRewrite**: rewrites the location protocol on (201/301/302/307/308) redirects to 'http' or 'https'. Default: null.
351* **cookieDomainRewrite**: rewrites domain of `set-cookie` headers. Possible values:
352 * `false` (default): disable cookie rewriting
353 * String: new domain, for example `cookieDomainRewrite: "new.domain"`. To remove the domain, use `cookieDomainRewrite: ""`.
354 * Object: mapping of domains to new domains, use `"*"` to match all domains.
355 For example keep one domain unchanged, rewrite one domain and remove other domains:
356 ```
357 cookieDomainRewrite: {
358 "unchanged.domain": "unchanged.domain",
359 "old.domain": "new.domain",
360 "*": ""
361 }
362 ```
363* **cookiePathRewrite**: rewrites path of `set-cookie` headers. Possible values:
364 * `false` (default): disable cookie rewriting
365 * String: new path, for example `cookiePathRewrite: "/newPath/"`. To remove the path, use `cookiePathRewrite: ""`. To set path to root use `cookiePathRewrite: "/"`.
366 * Object: mapping of paths to new paths, use `"*"` to match all paths.
367 For example, to keep one path unchanged, rewrite one path and remove other paths:
368 ```
369 cookiePathRewrite: {
370 "/unchanged.path/": "/unchanged.path/",
371 "/old.path/": "/new.path/",
372 "*": ""
373 }
374 ```
375* **headers**: object with extra headers to be added to target requests.
376* **proxyTimeout**: timeout (in millis) for outgoing proxy requests
377* **timeout**: timeout (in millis) for incoming requests
378* **followRedirects**: true/false, Default: false - specify whether you want to follow redirects
379* **selfHandleResponse** true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the `proxyRes` event
380* **buffer**: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option:
381
382 ```
383 'use strict';
384
385 const streamify = require('stream-array');
386 const HttpProxy = require('http-proxy');
387 const proxy = new HttpProxy();
388
389 module.exports = (req, res, next) => {
390
391 proxy.web(req, res, {
392 target: 'http://localhost:4003/',
393 buffer: streamify(req.rawBody)
394 }, next);
395
396 };
397 ```
398
399**NOTE:**
400`options.ws` and `options.ssl` are optional.
401`options.target` and `options.forward` cannot both be missing
402
403If you are using the `proxyServer.listen` method, the following options are also applicable:
404
405 * **ssl**: object to be passed to https.createServer()
406 * **ws**: true/false, if you want to proxy websockets
407
408
409**[Back to top](#table-of-contents)**
410
411### Listening for proxy events
412
413* `error`: The error event is emitted if the request to the target fail. **We do not do any error handling of messages passed between client and proxy, and messages passed between proxy and target, so it is recommended that you listen on errors and handle them.**
414* `proxyReq`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "web" connections
415* `proxyReqWs`: This event is emitted before the data is sent. It gives you a chance to alter the proxyReq request object. Applies to "websocket" connections
416* `proxyRes`: This event is emitted if the request to the target got a response.
417* `open`: This event is emitted once the proxy websocket was created and piped into the target websocket.
418* `close`: This event is emitted once the proxy websocket was closed.
419* (DEPRECATED) `proxySocket`: Deprecated in favor of `open`.
420
421```js
422var httpProxy = require('http-proxy');
423// Error example
424//
425// Http Proxy Server with bad target
426//
427var proxy = httpProxy.createServer({
428 target:'http://localhost:9005'
429});
430
431proxy.listen(8005);
432
433//
434// Listen for the `error` event on `proxy`.
435proxy.on('error', function (err, req, res) {
436 res.writeHead(500, {
437 'Content-Type': 'text/plain'
438 });
439
440 res.end('Something went wrong. And we are reporting a custom error message.');
441});
442
443//
444// Listen for the `proxyRes` event on `proxy`.
445//
446proxy.on('proxyRes', function (proxyRes, req, res) {
447 console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
448});
449
450//
451// Listen for the `open` event on `proxy`.
452//
453proxy.on('open', function (proxySocket) {
454 // listen for messages coming FROM the target here
455 proxySocket.on('data', hybiParseAndLogMessage);
456});
457
458//
459// Listen for the `close` event on `proxy`.
460//
461proxy.on('close', function (res, socket, head) {
462 // view disconnected websocket connections
463 console.log('Client disconnected');
464});
465```
466
467**[Back to top](#table-of-contents)**
468
469### Shutdown
470
471* When testing or running server within another program it may be necessary to close the proxy.
472* This will stop the proxy from accepting new connections.
473
474```js
475var proxy = new httpProxy.createProxyServer({
476 target: {
477 host: 'localhost',
478 port: 1337
479 }
480});
481
482proxy.close();
483```
484
485**[Back to top](#table-of-contents)**
486
487### Miscellaneous
488
489If you want to handle your own response after receiving the `proxyRes`, you can do
490so with `selfHandleResponse`. As you can see below, if you use this option, you
491are able to intercept and read the `proxyRes` but you must also make sure to
492reply to the `res` itself otherwise the original client will never receive any
493data.
494
495### Modify response
496
497```js
498
499 var option = {
500 target: target,
501 selfHandleResponse : true
502 };
503 proxy.on('proxyRes', function (proxyRes, req, res) {
504 var body = [];
505 proxyRes.on('data', function (chunk) {
506 body.push(chunk);
507 });
508 proxyRes.on('end', function () {
509 body = Buffer.concat(body).toString();
510 console.log("res from proxied server:", body);
511 res.end("my response to cli");
512 });
513 });
514 proxy.web(req, res, option);
515
516
517```
518
519#### ProxyTable API
520
521A proxy table API is available through this add-on [module](https://github.com/donasaur/http-proxy-rules), which lets you define a set of rules to translate matching routes to target routes that the reverse proxy will talk to.
522
523#### Test
524
525```
526$ npm test
527```
528
529#### Logo
530
531Logo created by [Diego Pasquali](http://dribbble.com/diegopq)
532
533**[Back to top](#table-of-contents)**
534
535### Contributing and Issues
536
537* Read carefully our [Code Of Conduct](https://github.com/http-party/node-http-proxy/blob/master/CODE_OF_CONDUCT.md)
538* Search on Google/Github
539* If you can't find anything, open an issue
540* If you feel comfortable about fixing the issue, fork the repo
541* Commit to your local branch (which must be different from `master`)
542* Submit your Pull Request (be sure to include tests and update documentation)
543
544**[Back to top](#table-of-contents)**
545
546### License
547
548>The MIT License (MIT)
549>
550>Copyright (c) 2010 - 2016 Charlie Robbins, Jarrett Cruger & the Contributors.
551>
552>Permission is hereby granted, free of charge, to any person obtaining a copy
553>of this software and associated documentation files (the "Software"), to deal
554>in the Software without restriction, including without limitation the rights
555>to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
556>copies of the Software, and to permit persons to whom the Software is
557>furnished to do so, subject to the following conditions:
558>
559>The above copyright notice and this permission notice shall be included in
560>all copies or substantial portions of the Software.
561>
562>THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
563>IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
564>FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
565>AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
566>LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
567>OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
568>THE SOFTWARE.