1 | # http-proxy-middleware
|
2 |
|
3 | [![Build Status](https://img.shields.io/travis/chimurai/http-proxy-middleware/master.svg?style=flat-square)](https://travis-ci.org/chimurai/http-proxy-middleware)
|
4 | [![Coveralls](https://img.shields.io/coveralls/chimurai/http-proxy-middleware.svg?style=flat-square)](https://coveralls.io/r/chimurai/http-proxy-middleware)
|
5 | [![dependency Status](https://img.shields.io/david/chimurai/http-proxy-middleware.svg?style=flat-square)](https://david-dm.org/chimurai/http-proxy-middleware#info=dependencies)
|
6 |
|
7 | Node.js proxying made simple. Configure proxy middleware with ease for [connect](https://github.com/senchalabs/connect), [express](https://github.com/strongloop/express), [browser-sync](https://github.com/BrowserSync/browser-sync) and [many more](#compatible-servers).
|
8 |
|
9 | Powered by the popular Nodejitsu [`http-proxy`](https://github.com/nodejitsu/node-http-proxy). [![GitHub stars](https://img.shields.io/github/stars/nodejitsu/node-http-proxy.svg?style=social&label=Star)](https://github.com/nodejitsu/node-http-proxy)
|
10 |
|
11 | ## TL;DR
|
12 |
|
13 | Proxy `/api` requests to `http://www.example.org`
|
14 |
|
15 | ```javascript
|
16 | var express = require('express');
|
17 | var proxy = require('http-proxy-middleware');
|
18 |
|
19 | var app = express();
|
20 |
|
21 | app.use('/api', proxy({target: 'http://www.example.org', changeOrigin: true}));
|
22 | app.listen(3000);
|
23 |
|
24 | // http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar
|
25 | ```
|
26 |
|
27 | _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#options) can be used, along with some extra `http-proxy-middleware` [options](#options).
|
28 |
|
29 | :bulb: **Tip:** Set the option `changeOrigin` to `true` for [name-based virtual hosted sites](http://en.wikipedia.org/wiki/Virtual_hosting#Name-based).
|
30 |
|
31 | ## Table of Contents
|
32 |
|
33 |
|
34 |
|
35 | - [Install](#install)
|
36 | - [Core concept](#core-concept)
|
37 | - [Example](#example)
|
38 | - [Context matching](#context-matching)
|
39 | - [Options](#options)
|
40 | - [http-proxy-middleware options](#http-proxy-middleware-options)
|
41 | - [http-proxy events](#http-proxy-events)
|
42 | - [http-proxy options](#http-proxy-options)
|
43 | - [Shorthand](#shorthand)
|
44 | - [app.use\(path, proxy\)](#appusepath-proxy)
|
45 | - [WebSocket](#websocket)
|
46 | - [External WebSocket upgrade](#external-websocket-upgrade)
|
47 | - [Working examples](#working-examples)
|
48 | - [Recipes](#recipes)
|
49 | - [Compatible servers](#compatible-servers)
|
50 | - [Tests](#tests)
|
51 | - [Changelog](#changelog)
|
52 | - [License](#license)
|
53 |
|
54 |
|
55 |
|
56 |
|
57 | ## Install
|
58 |
|
59 | ```javascript
|
60 | $ npm install --save-dev http-proxy-middleware
|
61 | ```
|
62 |
|
63 | ## Core concept
|
64 |
|
65 | Proxy middleware configuration.
|
66 |
|
67 | #### proxy([context,] config)
|
68 |
|
69 | ```javascript
|
70 | var proxy = require('http-proxy-middleware');
|
71 |
|
72 | var apiProxy = proxy('/api', {target: 'http://www.example.org'});
|
73 | // \____/ \_____________________________/
|
74 | // | |
|
75 | // context options
|
76 |
|
77 | // 'apiProxy' is now ready to be used as middleware in a server.
|
78 | ```
|
79 | * **context**: Determine which requests should be proxied to the target host.
|
80 | (more on [context matching](#context-matching))
|
81 | * **options.target**: target host to proxy to. _(protocol + host)_
|
82 |
|
83 | (full list of [`http-proxy-middleware` configuration options](#options))
|
84 |
|
85 | #### proxy(uri [, config])
|
86 |
|
87 | ``` javascript
|
88 | // shorthand syntax for the example above:
|
89 | var apiProxy = proxy('http://www.example.org/api');
|
90 |
|
91 | ```
|
92 | More about the [shorthand configuration](#shorthand).
|
93 |
|
94 | ## Example
|
95 |
|
96 | An example with `express` server.
|
97 |
|
98 | ```javascript
|
99 | // include dependencies
|
100 | var express = require('express');
|
101 | var proxy = require('http-proxy-middleware');
|
102 |
|
103 | // proxy middleware options
|
104 | var options = {
|
105 | target: 'http://www.example.org', // target host
|
106 | changeOrigin: true, // needed for virtual hosted sites
|
107 | ws: true, // proxy websockets
|
108 | pathRewrite: {
|
109 | '^/old/api' : '/new/api', // rewrite path
|
110 | '^/remove/api' : '/api' // remove path
|
111 | },
|
112 | proxyTable: {
|
113 | // when request.headers.host == 'dev.localhost:3000',
|
114 | // override target 'http://www.example.org' to 'http://localhost:8000'
|
115 | 'dev.localhost:3000' : 'http://localhost:8000'
|
116 | }
|
117 | };
|
118 |
|
119 | // create the proxy (without context)
|
120 | var exampleProxy = proxy(options);
|
121 |
|
122 | // mount `exampleProxy` in web server
|
123 | var app = express();
|
124 | app.use('/api', exampleProxy);
|
125 | app.listen(3000);
|
126 | ```
|
127 |
|
128 | ## Context matching
|
129 |
|
130 | Providing an alternative way to decide which requests should be proxied; In case you are not able to use the server's [`path` parameter](http://expressjs.com/en/4x/api.html#app.use) to mount the proxy or when you need more flexibility. Request URL's [ _path-absolute_ and _query_](https://tools.ietf.org/html/rfc3986#section-3) will be used for context matching.
|
131 |
|
132 | * **path matching**
|
133 | - `proxy({...})` or `proxy('/', {...})` - matches any path, all requests will be proxied.
|
134 | - `proxy('/api', {...})` - matches paths starting with `/api`
|
135 |
|
136 | * **multiple path matching**
|
137 | - `proxy(['/api', '/ajax', '/someotherpath'], {...})`
|
138 |
|
139 | * **wildcard path matching**
|
140 |
|
141 | For fine-grained control you can use wildcard matching. Glob pattern matching is done by _micromatch_. Visit [micromatch](https://www.npmjs.com/package/micromatch) or [glob](https://www.npmjs.com/package/glob) for more globbing examples.
|
142 | - `proxy('**', {...})` matches any path, all requests will be proxied.
|
143 | - `proxy('**/*.html', {...})` matches any path which ends with `.html`
|
144 | - `proxy('/*.html', {...})` matches paths directly under path-absolute
|
145 | - `proxy('/api/**/*.html', {...})` matches requests ending with `.html` in the path of `/api`
|
146 | - `proxy(['/api/**', '/ajax/**'], {...})` combine multiple patterns
|
147 | - `proxy(['/api/**', '!**/bad.json'], {...})` exclusion
|
148 |
|
149 | * **custom matching**
|
150 |
|
151 | For full control you can provide a custom function to determine which requests should be proxied or not.
|
152 | ```javascript
|
153 | /**
|
154 | * @return {Boolean}
|
155 | */
|
156 | var filter = function (path, req) {
|
157 | return (path.match('^/api') && req.method === 'GET');
|
158 | };
|
159 |
|
160 | var apiProxy = proxy(filter, {target: 'http://www.example.org'})
|
161 | ```
|
162 |
|
163 | ## Options
|
164 |
|
165 | ### http-proxy-middleware options
|
166 |
|
167 | * **option.pathRewrite**: object/function, rewrite target's url path. Object-keys will be used as _RegExp_ to match paths.
|
168 | ```javascript
|
169 | // rewrite path
|
170 | pathRewrite: {'^/old/api' : '/new/api'}
|
171 |
|
172 | // remove path
|
173 | pathRewrite: {'^/remove/api' : ''}
|
174 |
|
175 | // add base path
|
176 | pathRewrite: {'^/' : '/basepath/'}
|
177 |
|
178 | // custom rewriting
|
179 | pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }
|
180 | ```
|
181 |
|
182 | * **option.proxyTable**: object, re-target `option.target` based on the request header `host` parameter. `host` can be used in conjunction with `path`. Only one instance of the proxy will be used. The order of the configuration matters.
|
183 | ```javascript
|
184 | proxyTable: {
|
185 | 'integration.localhost:3000' : 'http://localhost:8001', // host only
|
186 | 'staging.localhost:3000' : 'http://localhost:8002', // host only
|
187 | 'localhost:3000/api' : 'http://localhost:8003', // host + path
|
188 | '/rest' : 'http://localhost:8004' // path only
|
189 | }
|
190 | ```
|
191 |
|
192 | * **option.logLevel**: string, ['debug', 'info', 'warn', 'error', 'silent']. Default: `'info'`
|
193 |
|
194 | * **option.logProvider**: function, modify or replace log provider. Default: `console`.
|
195 | ```javascript
|
196 | // simple replace
|
197 | function logProvider(provider) {
|
198 | // replace the default console log provider.
|
199 | return require('winston');
|
200 | }
|
201 | ```
|
202 |
|
203 | ```javascript
|
204 | // verbose replacement
|
205 | function logProvider(provider) {
|
206 | var logger = new (require('winston').Logger)();
|
207 |
|
208 | var myCustomProvider = {
|
209 | log: logger.log,
|
210 | debug: logger.debug,
|
211 | info: logger.info,
|
212 | warn: logger.warn,
|
213 | error: logger.error
|
214 | }
|
215 | return myCustomProvider;
|
216 | }
|
217 | ```
|
218 | * (DEPRECATED) **option.proxyHost**: Use `option.changeOrigin = true` instead.
|
219 |
|
220 |
|
221 | ### http-proxy events
|
222 |
|
223 | Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events):
|
224 |
|
225 | * **option.onError**: function, subscribe to http-proxy's `error` event for custom error handling.
|
226 | ```javascript
|
227 | function onError(err, req, res) {
|
228 | res.writeHead(500, {
|
229 | 'Content-Type': 'text/plain'
|
230 | });
|
231 | res.end('Something went wrong. And we are reporting a custom error message.');
|
232 | }
|
233 | ```
|
234 |
|
235 | * **option.onProxyRes**: function, subscribe to http-proxy's `proxyRes` event.
|
236 | ```javascript
|
237 | function onProxyRes(proxyRes, req, res) {
|
238 | proxyRes.headers['x-added'] = 'foobar'; // add new header to response
|
239 | delete proxyRes.headers['x-removed']; // remove header from response
|
240 | }
|
241 | ```
|
242 |
|
243 | * **option.onProxyReq**: function, subscribe to http-proxy's `proxyReq` event.
|
244 | ```javascript
|
245 | function onProxyReq(proxyReq, req, res) {
|
246 | // add custom header to request
|
247 | proxyReq.setHeader('x-added', 'foobar');
|
248 | // or log the req
|
249 | }
|
250 | ```
|
251 |
|
252 | * **option.onProxyReqWs**: function, subscribe to http-proxy's `proxyReqWs` event.
|
253 | ```javascript
|
254 | function onProxyReqWs(proxyReq, req, socket, options, head) {
|
255 | // add custom header
|
256 | proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
|
257 | }
|
258 | ```
|
259 |
|
260 | * **option.onOpen**: function, subscribe to http-proxy's `open` event.
|
261 | ```javascript
|
262 | function onOpen(proxySocket) {
|
263 | // listen for messages coming FROM the target here
|
264 | proxySocket.on('data', hybiParseAndLogMessage);
|
265 | }
|
266 | ```
|
267 |
|
268 | * **option.onClose**: function, subscribe to http-proxy's `close` event.
|
269 | ```javascript
|
270 | function onClose(res, socket, head) {
|
271 | // view disconnected websocket connections
|
272 | console.log('Client disconnected');
|
273 | }
|
274 | ```
|
275 |
|
276 | ### http-proxy options
|
277 |
|
278 | The following options are provided by the underlying [http-proxy](https://github.com/nodejitsu/node-http-proxy#options) library.
|
279 |
|
280 | * **option.target**: url string to be parsed with the url module
|
281 | * **option.forward**: url string to be parsed with the url module
|
282 | * **option.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)
|
283 | * **option.ssl**: object to be passed to https.createServer()
|
284 | * **option.ws**: true/false: if you want to proxy websockets
|
285 | * **option.xfwd**: true/false, adds x-forward headers
|
286 | * **option.secure**: true/false, if you want to verify the SSL Certs
|
287 | * **option.toProxy**: true/false, passes the absolute URL as the `path` (useful for proxying to proxies)
|
288 | * **option.prependPath**: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path>
|
289 | * **option.ignorePath**: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request>
|
290 | * **option.localAddress** : Local interface string to bind for outgoing connections
|
291 | * **option.changeOrigin**: true/false, adds host to request header.
|
292 | * **option.auth** : Basic authentication i.e. 'user:password' to compute an Authorization header.
|
293 | * **option.hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects.
|
294 | * **option.autoRewrite**: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.
|
295 | * **option.protocolRewrite**: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.
|
296 | * **option.headers**: object, adds [request headers](https://en.wikipedia.org/wiki/List_of_HTTP_header_fields#Request_fields). (Example: `{host:'www.example.org'}`)
|
297 |
|
298 |
|
299 | ## Shorthand
|
300 |
|
301 | Use the shorthand syntax when verbose configuration is not needed. The `context` and `option.target` will be automatically configured when shorthand is used. Options can still be used if needed.
|
302 |
|
303 | ```javascript
|
304 | proxy('http://www.example.org:8000/api');
|
305 | // proxy('/api', {target: 'http://www.example.org:8000'});
|
306 |
|
307 |
|
308 | proxy('http://www.example.org:8000/api/books/*/**.json');
|
309 | // proxy('/api/books/*/**.json', {target: 'http://www.example.org:8000'});
|
310 |
|
311 |
|
312 | proxy('http://www.example.org:8000/api', {changeOrigin:true});
|
313 | // proxy('/api', {target: 'http://www.example.org:8000', changeOrigin: true});
|
314 | ```
|
315 |
|
316 | ### app.use(path, proxy)
|
317 |
|
318 | If you want to use the server's `app.use` `path` parameter to match requests;
|
319 | Create and mount the proxy without the http-proxy-middleware `context` parameter:
|
320 | ```javascript
|
321 | app.use('/api', proxy({target:'http://www.example.org', changeOrigin:true}));
|
322 | ```
|
323 |
|
324 | `app.use` documentation:
|
325 | * express: http://expressjs.com/en/4x/api.html#app.use
|
326 | * connect: https://github.com/senchalabs/connect#mount-middleware
|
327 |
|
328 | ## WebSocket
|
329 |
|
330 | ```javascript
|
331 | // verbose api
|
332 | proxy('/', {target:'http://echo.websocket.org', ws:true});
|
333 |
|
334 | // shorthand
|
335 | proxy('http://echo.websocket.org', {ws:true});
|
336 |
|
337 | // shorter shorthand
|
338 | proxy('ws://echo.websocket.org');
|
339 | ```
|
340 |
|
341 | ### External WebSocket upgrade
|
342 |
|
343 | In the previous WebSocket examples, http-proxy-middleware relies on a initial http request in order to listen to the http `upgrade` event. If you need to proxy WebSockets without the initial http request, you can subscribe to the server's http `upgrade` event manually.
|
344 | ```javascript
|
345 | var wsProxy = proxy('ws://echo.websocket.org', {changeOrigin:true});
|
346 |
|
347 | var app = express();
|
348 | app.use(wsProxy);
|
349 |
|
350 | var server = app.listen(3000);
|
351 | server.on('upgrade', wsProxy.upgrade); // <-- subscribe to http 'upgrade'
|
352 | ```
|
353 |
|
354 |
|
355 | ## Working examples
|
356 |
|
357 | View and play around with [working examples](https://github.com/chimurai/http-proxy-middleware/tree/master/examples).
|
358 |
|
359 | * Browser-Sync ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/browser-sync/index.js))
|
360 | * express ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/express/index.js))
|
361 | * connect ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/connect/index.js))
|
362 | * WebSocket ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/websocket/index.js))
|
363 |
|
364 | ## Recipes
|
365 |
|
366 | View the [recipes](https://github.com/chimurai/http-proxy-middleware/tree/master/recipes) for common use cases.
|
367 |
|
368 | ## Compatible servers
|
369 |
|
370 | `http-proxy-middleware` is compatible with the following servers:
|
371 | * [connect](https://www.npmjs.com/package/connect)
|
372 | * [express](https://www.npmjs.com/package/express)
|
373 | * [browser-sync](https://www.npmjs.com/package/browser-sync)
|
374 | * [lite-server](https://www.npmjs.com/package/lite-server)
|
375 | * [grunt-contrib-connect](https://www.npmjs.com/package/grunt-contrib-connect)
|
376 | * [grunt-browser-sync](https://www.npmjs.com/package/grunt-browser-sync)
|
377 | * [gulp-connect](https://www.npmjs.com/package/gulp-connect)
|
378 | * [gulp-webserver](https://www.npmjs.com/package/gulp-webserver)
|
379 |
|
380 | Sample implementations can be found in the [server recipes](https://github.com/chimurai/http-proxy-middleware/tree/master/recipes/servers.md).
|
381 |
|
382 | ## Tests
|
383 |
|
384 | Run the test suite:
|
385 |
|
386 | ```bash
|
387 | # install dependencies
|
388 | $ npm install
|
389 | ```
|
390 |
|
391 | unit testing
|
392 |
|
393 | ```bash
|
394 | # unit tests
|
395 | $ npm test
|
396 | ```
|
397 |
|
398 | coverage
|
399 |
|
400 | ```bash
|
401 | # code coverage
|
402 | $ npm run cover
|
403 | ```
|
404 |
|
405 | ## Changelog
|
406 |
|
407 | - [View changelog](https://github.com/chimurai/http-proxy-middleware/blob/master/CHANGELOG.md)
|
408 |
|
409 |
|
410 | ## License
|
411 |
|
412 | The MIT License (MIT)
|
413 |
|
414 | Copyright (c) 2015-2016 Steven Chim
|