1 | <p align="center">
|
2 | <img src="https://raw.github.com/nodejitsu/node-http-proxy/master/doc/logo.png"/>
|
3 | </p>
|
4 |
|
5 | node-http-proxy
|
6 | =======
|
7 |
|
8 | `node-http-proxy` is an HTTP programmable proxying library that supports
|
9 | websockets. It is suitable for implementing components such as
|
10 | proxies and load balancers.
|
11 |
|
12 | ### Installation
|
13 |
|
14 | `npm install http-proxy --save`
|
15 |
|
16 | ### Build Status
|
17 |
|
18 | <p align="center">
|
19 | <a href="https://travis-ci.org/nodejitsu/node-http-proxy" target="_blank">
|
20 | <img src="https://travis-ci.org/nodejitsu/node-http-proxy.png"/></a>
|
21 | <a href="https://coveralls.io/r/nodejitsu/node-http-proxy" target="_blank">
|
22 | <img src="https://coveralls.io/repos/nodejitsu/node-http-proxy/badge.png"/></a>
|
23 | </p>
|
24 |
|
25 | ### Looking to Upgrade from 0.8.x ? Click [here](UPGRADING.md)
|
26 |
|
27 | ### Core Concept
|
28 |
|
29 | A new proxy is created by calling `createProxyServer` and passing
|
30 | an `options` object as argument ([valid properties are available here](lib/http-proxy.js#L33-L50))
|
31 |
|
32 | ```javascript
|
33 | var httpProxy = require('http-proxy');
|
34 |
|
35 | var proxy = httpProxy.createProxyServer(options);
|
36 | ```
|
37 |
|
38 | An object will be returned with four values:
|
39 |
|
40 | * web `req, res, [options]` (used for proxying regular HTTP(S) requests)
|
41 | * ws `req, socket, head, [options]` (used for proxying WS(S) requests)
|
42 | * listen `port` (a function that wraps the object in a webserver, for your convenience)
|
43 | * close `[callback]` (a function that closes the inner webserver and stops listening on given port)
|
44 |
|
45 | It is then possible to proxy requests by calling these functions
|
46 |
|
47 | ```javascript
|
48 | http.createServer(function(req, res) {
|
49 | proxy.web(req, res, { target: 'http://mytarget.com:8080' });
|
50 | });
|
51 | ```
|
52 |
|
53 | Errors can be listened on either using the Event Emitter API
|
54 |
|
55 | ```javascript
|
56 | proxy.on('error', function(e) {
|
57 | ...
|
58 | });
|
59 | ```
|
60 |
|
61 | or using the callback API
|
62 |
|
63 | ```javascript
|
64 | proxy.web(req, res, { target: 'http://mytarget.com:8080' }, function(e) { ... });
|
65 | ```
|
66 |
|
67 | When a request is proxied it follows two different pipelines ([available here](lib/http-proxy/passes))
|
68 | which apply transformations to both the `req` and `res` object.
|
69 | The first pipeline (ingoing) is responsible for the creation and manipulation of the stream that connects your client to the target.
|
70 | The second pipeline (outgoing) is responsible for the creation and manipulation of the stream that, from your target, returns data
|
71 | to the client.
|
72 |
|
73 |
|
74 | #### Setup a basic stand-alone proxy server
|
75 |
|
76 | ```js
|
77 | var http = require('http'),
|
78 | httpProxy = require('http-proxy');
|
79 | //
|
80 | // Create your proxy server and set the target in the options.
|
81 | //
|
82 | httpProxy.createProxyServer({target:'http://localhost:9000'}).listen(8000);
|
83 |
|
84 | //
|
85 | // Create your target server
|
86 | //
|
87 | http.createServer(function (req, res) {
|
88 | res.writeHead(200, { 'Content-Type': 'text/plain' });
|
89 | res.write('request successfully proxied!' + '\n' + JSON.stringify(req.headers, true, 2));
|
90 | res.end();
|
91 | }).listen(9000);
|
92 | ```
|
93 |
|
94 | #### Setup a stand-alone proxy server with custom server logic
|
95 | This example show how you can proxy a request using your own HTTP server
|
96 | and also you can put your own logic to handle the request.
|
97 |
|
98 | ```js
|
99 | var http = require('http'),
|
100 | httpProxy = require('http-proxy');
|
101 |
|
102 | //
|
103 | // Create a proxy server with custom application logic
|
104 | //
|
105 | var proxy = httpProxy.createProxyServer({});
|
106 |
|
107 | //
|
108 | // Create your custom server and just call `proxy.web()` to proxy
|
109 | // a web request to the target passed in the options
|
110 | // also you can use `proxy.ws()` to proxy a websockets request
|
111 | //
|
112 | var server = http.createServer(function(req, res) {
|
113 | // You can define here your custom logic to handle the request
|
114 | // and then proxy the request.
|
115 | proxy.web(req, res, { target: 'http://127.0.0.1:5060' });
|
116 | });
|
117 |
|
118 | console.log("listening on port 5050")
|
119 | server.listen(5050);
|
120 | ```
|
121 | #### Modify a response from a proxied server
|
122 | Sometimes when you have received a HTML/XML document from the server of origin you would like to modify it before forwarding it on.
|
123 |
|
124 | [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.
|
125 |
|
126 |
|
127 | #### Setup a stand-alone proxy server with proxy request header re-writing
|
128 | This example shows how you can proxy a request using your own HTTP server that
|
129 | modifies the outgoing proxy request by adding a special header.
|
130 |
|
131 | ```js
|
132 | var http = require('http'),
|
133 | httpProxy = require('http-proxy');
|
134 |
|
135 | //
|
136 | // Create a proxy server with custom application logic
|
137 | //
|
138 | var proxy = httpProxy.createProxyServer({});
|
139 |
|
140 | // To modify the proxy connection before data is sent, you can listen
|
141 | // for the 'proxyReq' event. When the event is fired, you will receive
|
142 | // the following arguments:
|
143 | // (http.ClientRequest proxyReq, http.IncomingMessage req,
|
144 | // http.ServerResponse res, Object options). This mechanism is useful when
|
145 | // you need to modify the proxy request before the proxy connection
|
146 | // is made to the target.
|
147 | //
|
148 | proxy.on('proxyReq', function(proxyReq, req, res, options) {
|
149 | proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
|
150 | });
|
151 |
|
152 | var server = http.createServer(function(req, res) {
|
153 | // You can define here your custom logic to handle the request
|
154 | // and then proxy the request.
|
155 | proxy.web(req, res, {
|
156 | target: 'http://127.0.0.1:5060'
|
157 | });
|
158 | });
|
159 |
|
160 | console.log("listening on port 5050")
|
161 | server.listen(5050);
|
162 | ```
|
163 |
|
164 | #### Setup a stand-alone proxy server with latency
|
165 |
|
166 | ```js
|
167 | var http = require('http'),
|
168 | httpProxy = require('http-proxy');
|
169 |
|
170 | //
|
171 | // Create a proxy server with latency
|
172 | //
|
173 | var proxy = httpProxy.createProxyServer();
|
174 |
|
175 | //
|
176 | // Create your server that makes an operation that waits a while
|
177 | // and then proxies the request
|
178 | //
|
179 | http.createServer(function (req, res) {
|
180 | // This simulates an operation that takes 500ms to execute
|
181 | setTimeout(function () {
|
182 | proxy.web(req, res, {
|
183 | target: 'http://localhost:9008'
|
184 | });
|
185 | }, 500);
|
186 | }).listen(8008);
|
187 |
|
188 | //
|
189 | // Create your target server
|
190 | //
|
191 | http.createServer(function (req, res) {
|
192 | res.writeHead(200, { 'Content-Type': 'text/plain' });
|
193 | res.write('request successfully proxied to: ' + req.url + '\n' + JSON.stringify(req.headers, true, 2));
|
194 | res.end();
|
195 | }).listen(9008);
|
196 | ```
|
197 |
|
198 | #### Listening for proxy events
|
199 |
|
200 | * `error`: The error event is emitted if the request to the target fail.
|
201 | * `proxyRes`: This event is emitted if the request to the target got a response.
|
202 | * `open`: This event is emitted once the proxy websocket was created and piped into the target websocket.
|
203 | * `close`: This event is emitted once the proxy websocket was closed.
|
204 | * (DEPRECATED) `proxySocket`: Deprecated in favor of `open`.
|
205 |
|
206 | ```js
|
207 | var httpProxy = require('http-proxy');
|
208 | // Error example
|
209 | //
|
210 | // Http Proxy Server with bad target
|
211 | //
|
212 | var proxy = httpProxy.createServer({
|
213 | target:'http://localhost:9005'
|
214 | });
|
215 |
|
216 | proxy.listen(8005);
|
217 |
|
218 | //
|
219 | // Listen for the `error` event on `proxy`.
|
220 | proxy.on('error', function (err, req, res) {
|
221 | res.writeHead(500, {
|
222 | 'Content-Type': 'text/plain'
|
223 | });
|
224 |
|
225 | res.end('Something went wrong. And we are reporting a custom error message.');
|
226 | });
|
227 |
|
228 | //
|
229 | // Listen for the `proxyRes` event on `proxy`.
|
230 | //
|
231 | proxy.on('proxyRes', function (proxyRes, req, res) {
|
232 | console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2));
|
233 | });
|
234 |
|
235 | //
|
236 | // Listen for the `open` event on `proxy`.
|
237 | //
|
238 | proxy.on('open', function (proxySocket) {
|
239 | // listen for messages coming FROM the target here
|
240 | proxySocket.on('data', hybiParseAndLogMessage);
|
241 | });
|
242 |
|
243 | //
|
244 | // Listen for the `close` event on `proxy`.
|
245 | //
|
246 | proxy.on('close', function (req, socket, head) {
|
247 | // view disconnected websocket connections
|
248 | console.log('Client disconnected');
|
249 | });
|
250 | ```
|
251 |
|
252 | #### Using HTTPS
|
253 | You can activate the validation of a secure SSL certificate to the target connection (avoid self signed certs), just set `secure: true` in the options.
|
254 |
|
255 | ##### HTTPS -> HTTP
|
256 |
|
257 | ```js
|
258 | //
|
259 | // Create the HTTPS proxy server in front of a HTTP server
|
260 | //
|
261 | httpProxy.createServer({
|
262 | target: {
|
263 | host: 'localhost',
|
264 | port: 9009
|
265 | },
|
266 | ssl: {
|
267 | key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
|
268 | cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
|
269 | }
|
270 | }).listen(8009);
|
271 | ```
|
272 |
|
273 | ##### HTTPS -> HTTPS
|
274 |
|
275 | ```js
|
276 | //
|
277 | // Create the proxy server listening on port 443
|
278 | //
|
279 | httpProxy.createServer({
|
280 | ssl: {
|
281 | key: fs.readFileSync('valid-ssl-key.pem', 'utf8'),
|
282 | cert: fs.readFileSync('valid-ssl-cert.pem', 'utf8')
|
283 | },
|
284 | target: 'https://localhost:9010',
|
285 | secure: true // Depends on your needs, could be false.
|
286 | }).listen(443);
|
287 | ```
|
288 |
|
289 | #### Proxying WebSockets
|
290 | You can activate the websocket support for the proxy using `ws:true` in the options.
|
291 |
|
292 | ```js
|
293 | //
|
294 | // Create a proxy server for websockets
|
295 | //
|
296 | httpProxy.createServer({
|
297 | target: 'ws://localhost:9014',
|
298 | ws: true
|
299 | }).listen(8014);
|
300 | ```
|
301 |
|
302 | Also you can proxy the websocket requests just calling the `ws(req, socket, head)` method.
|
303 |
|
304 | ```js
|
305 | //
|
306 | // Setup our server to proxy standard HTTP requests
|
307 | //
|
308 | var proxy = new httpProxy.createProxyServer({
|
309 | target: {
|
310 | host: 'localhost',
|
311 | port: 9015
|
312 | }
|
313 | });
|
314 | var proxyServer = http.createServer(function (req, res) {
|
315 | proxy.web(req, res);
|
316 | });
|
317 |
|
318 | //
|
319 | // Listen to the `upgrade` event and proxy the
|
320 | // WebSocket requests as well.
|
321 | //
|
322 | proxyServer.on('upgrade', function (req, socket, head) {
|
323 | proxy.ws(req, socket, head);
|
324 | });
|
325 |
|
326 | proxyServer.listen(8015);
|
327 | ```
|
328 |
|
329 | ### Contributing and Issues
|
330 |
|
331 | * Search on Google/Github
|
332 | * If you can't find anything, open an issue
|
333 | * If you feel comfortable about fixing the issue, fork the repo
|
334 | * Commit to your local branch (which must be different from `master`)
|
335 | * Submit your Pull Request (be sure to include tests and update documentation)
|
336 |
|
337 | ### Options
|
338 |
|
339 | `httpProxy.createProxyServer` supports the following options:
|
340 |
|
341 | * **target**: url string to be parsed with the url module
|
342 | * **forward**: url string to be parsed with the url module
|
343 | * **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)
|
344 | * **ssl**: object to be passed to https.createServer()
|
345 | * **ws**: true/false, if you want to proxy websockets
|
346 | * **xfwd**: true/false, adds x-forward headers
|
347 | * **secure**: true/false, if you want to verify the SSL Certs
|
348 | * **toProxy**: passes the absolute URL as the `path` (useful for proxying to proxies)
|
349 | * **prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path
|
350 | * **ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request
|
351 | * **localAddress**: Local interface string to bind for outgoing connections
|
352 | * **changeOrigin**: true/false, Default: false - changes the origin of the host header to the target URL
|
353 | * **auth**: Basic authentication i.e. 'user:password' to compute an Authorization header.
|
354 | * **hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects.
|
355 | * **autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.
|
356 | * **protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.
|
357 |
|
358 | **NOTE:**
|
359 | `options.ws` and `options.ssl` are optional.
|
360 | `options.target` and `options.forward` cannot both be missing
|
361 |
|
362 | If you are using the `proxyServer.listen` method, the following options are also applicable:
|
363 |
|
364 | * **ssl**: object to be passed to https.createServer()
|
365 | * **ws**: true/false, if you want to proxy websockets
|
366 |
|
367 | ### Shutdown
|
368 |
|
369 | * When testing or running server within another program it may be necessary to close the proxy.
|
370 | * This will stop the proxy from accepting new connections.
|
371 |
|
372 | ```js
|
373 | var proxy = new httpProxy.createProxyServer({
|
374 | target: {
|
375 | host: 'localhost',
|
376 | port: 1337
|
377 | }
|
378 | });
|
379 |
|
380 | proxy.close();
|
381 | ```
|
382 |
|
383 | ### Test
|
384 |
|
385 | ```
|
386 | $ npm test
|
387 | ```
|
388 |
|
389 | ### Logo
|
390 |
|
391 | Logo created by [Diego Pasquali](http://dribbble.com/diegopq)
|
392 |
|
393 | ### License
|
394 |
|
395 | >The MIT License (MIT)
|
396 | >
|
397 | >Copyright (c) 2010 - 2013 Nodejitsu Inc.
|
398 | >
|
399 | >Permission is hereby granted, free of charge, to any person obtaining a copy
|
400 | >of this software and associated documentation files (the "Software"), to deal
|
401 | >in the Software without restriction, including without limitation the rights
|
402 | >to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
403 | >copies of the Software, and to permit persons to whom the Software is
|
404 | >furnished to do so, subject to the following conditions:
|
405 | >
|
406 | >The above copyright notice and this permission notice shall be included in
|
407 | >all copies or substantial portions of the Software.
|
408 | >
|
409 | >THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
410 | >IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
411 | >FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
412 | >AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
413 | >LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
414 | >OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
415 | >THE SOFTWARE.
|
416 |
|
417 |
|