Skip to content

Commit fc57510

Browse files
committed
feat(option): refactor context to pathFilter option [BREAKING CHANGE]
1 parent 1540dac commit fc57510

22 files changed

+554
-609
lines changed

README.md

Lines changed: 120 additions & 110 deletions
Original file line numberDiff line numberDiff line change
@@ -56,13 +56,16 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
5656

5757
- [Install](#install)
5858
- [Core concept](#core-concept)
59-
- [Example](#example)
59+
- [Express Server Example](#express-server-example)
6060
- [app.use(path, proxy)](#appusepath-proxy)
61-
- [Context matching](#context-matching)
6261
- [Options](#options)
63-
- [http-proxy-middleware options](#http-proxy-middleware-options)
64-
- [http-proxy events](#http-proxy-events)
65-
- [http-proxy options](#http-proxy-options)
62+
- [`pathFilter` (string, []string, glob, []glob, function)](#pathfilter-string-string-glob-glob-function)
63+
- [`pathRewrite` (object/function)](#pathrewrite-objectfunction)
64+
- [`router` (object/function)](#router-objectfunction)
65+
- [`logLevel` (string)](#loglevel-string)
66+
- [`logProvider` (function)](#logprovider-function)
67+
- [`http-proxy` events](#http-proxy-events)
68+
- [`http-proxy` options](#http-proxy-options)
6669
- [WebSocket](#websocket)
6770
- [External WebSocket upgrade](#external-websocket-upgrade)
6871
- [Intercept and manipulate requests](#intercept-and-manipulate-requests)
@@ -76,34 +79,32 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
7679

7780
## Install
7881

79-
```bash
80-
$ npm install --save-dev http-proxy-middleware
82+
```shell
83+
npm install --save-dev http-proxy-middleware
8184
```
8285

8386
## Core concept
8487

85-
Proxy middleware configuration.
86-
87-
#### createProxyMiddleware([context,] config)
88+
Create and configure a proxy middleware with: `createProxyMiddleware(config)`.
8889

8990
```javascript
9091
const { createProxyMiddleware } = require('http-proxy-middleware');
9192

92-
const apiProxy = createProxyMiddleware('/api', { target: 'http://www.example.org' });
93-
// \____/ \_____________________________/
94-
// | |
95-
// context options
93+
const apiProxy = createProxyMiddleware({
94+
pathFilter: '/api',
95+
target: 'http://www.example.org',
96+
});
9697

9798
// 'apiProxy' is now ready to be used as middleware in a server.
9899
```
99100

100-
- **context**: Determine which requests should be proxied to the target host.
101-
(more on [context matching](#context-matching))
101+
- **options.pathFilter**: Determine which requests should be proxied to the target host.
102+
(more on [path filter](#path-filter))
102103
- **options.target**: target host to proxy to. _(protocol + host)_
103104

104-
(full list of [`http-proxy-middleware` configuration options](#options))
105+
- see full list of [`http-proxy-middleware` configuration options](#options)
105106

106-
## Example
107+
## Express Server Example
107108

108109
An example with `express` server.
109110

@@ -129,7 +130,7 @@ const options = {
129130
},
130131
};
131132

132-
// create the proxy (without context)
133+
// create the proxy
133134
const exampleProxy = createProxyMiddleware(options);
134135

135136
// mount `exampleProxy` in web server
@@ -140,8 +141,8 @@ app.listen(3000);
140141

141142
### app.use(path, proxy)
142143

143-
If you want to use the server's `app.use` `path` parameter to match requests;
144-
Create and mount the proxy without the http-proxy-middleware `context` parameter:
144+
If you want to use the server's `app.use` `path` parameter to match requests.
145+
Use `pathFilter` option to further include/exclude requests which you want to proxy.
145146

146147
```javascript
147148
app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true }));
@@ -153,11 +154,15 @@ app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', change
153154
- connect: https://github.com/senchalabs/connect#mount-middleware
154155
- polka: https://github.com/lukeed/polka#usebase-fn
155156

156-
## Context matching
157+
## Options
158+
159+
http-proxy-middleware options:
157160

158-
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.
161+
### `pathFilter` (string, []string, glob, []glob, function)
159162

160-
[RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used for context matching.
163+
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.
164+
165+
[RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used in `pathFilter`.
161166

162167
```ascii
163168
foo://example.com:8042/over/there?name=ferret#nose
@@ -169,23 +174,22 @@ Providing an alternative way to decide which requests should be proxied; In case
169174
- **path matching**
170175

171176
- `createProxyMiddleware({...})` - matches any path, all requests will be proxied.
172-
- `createProxyMiddleware('/', {...})` - matches any path, all requests will be proxied.
173-
- `createProxyMiddleware('/api', {...})` - matches paths starting with `/api`
177+
- `createProxyMiddleware({ pathFilter: '/api', ...})` - matches paths starting with `/api`
174178

175179
- **multiple path matching**
176180

177-
- `createProxyMiddleware(['/api', '/ajax', '/someotherpath'], {...})`
181+
- `createProxyMiddleware({ pathFilter: ['/api', '/ajax', '/someotherpath'], ...})`
178182

179183
- **wildcard path matching**
180184

181185
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.
182186

183-
- `createProxyMiddleware('**', {...})` matches any path, all requests will be proxied.
184-
- `createProxyMiddleware('**/*.html', {...})` matches any path which ends with `.html`
185-
- `createProxyMiddleware('/*.html', {...})` matches paths directly under path-absolute
186-
- `createProxyMiddleware('/api/**/*.html', {...})` matches requests ending with `.html` in the path of `/api`
187-
- `createProxyMiddleware(['/api/**', '/ajax/**'], {...})` combine multiple patterns
188-
- `createProxyMiddleware(['/api/**', '!**/bad.json'], {...})` exclusion
187+
- `createProxyMiddleware({ pathFilter: '**', ...})` matches any path, all requests will be proxied.
188+
- `createProxyMiddleware({ pathFilter: '**/*.html', ...})` matches any path which ends with `.html`
189+
- `createProxyMiddleware({ pathFilter: '/*.html', ...})` matches paths directly under path-absolute
190+
- `createProxyMiddleware({ pathFilter: '/api/**/*.html', ...})` matches requests ending with `.html` in the path of `/api`
191+
- `createProxyMiddleware({ pathFilter: ['/api/**', '/ajax/**'], ...})` combine multiple patterns
192+
- `createProxyMiddleware({ pathFilter: ['/api/**', '!**/bad.json'], ...})` exclusion
189193

190194
**Note**: In multiple path matching, you cannot use string paths and wildcard paths together.
191195

@@ -197,104 +201,110 @@ Providing an alternative way to decide which requests should be proxied; In case
197201
/**
198202
* @return {Boolean}
199203
*/
200-
const filter = function (pathname, req) {
201-
return pathname.match('^/api') && req.method === 'GET';
204+
const filter = function (path, req) {
205+
return path.match('^/api') && req.method === 'GET';
202206
};
203207

204208
const apiProxy = createProxyMiddleware(filter, {
205209
target: 'http://www.example.org',
206210
});
207211
```
208212

209-
## Options
213+
### `pathRewrite` (object/function)
210214

211-
### http-proxy-middleware options
215+
Rewrite target's url path. Object-keys will be used as _RegExp_ to match paths.
212216

213-
- **option.pathRewrite**: object/function, rewrite target's url path. Object-keys will be used as _RegExp_ to match paths.
217+
```javascript
218+
// rewrite path
219+
pathRewrite: {'^/old/api' : '/new/api'}
214220

215-
```javascript
216-
// rewrite path
217-
pathRewrite: {'^/old/api' : '/new/api'}
221+
// remove path
222+
pathRewrite: {'^/remove/api' : ''}
218223

219-
// remove path
220-
pathRewrite: {'^/remove/api' : ''}
224+
// add base path
225+
pathRewrite: {'^/' : '/basepath/'}
221226

222-
// add base path
223-
pathRewrite: {'^/' : '/basepath/'}
227+
// custom rewriting
228+
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }
224229

225-
// custom rewriting
226-
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }
230+
// custom rewriting, returning Promise
231+
pathRewrite: async function (path, req) {
232+
const should_add_something = await httpRequestToDecideSomething(path);
233+
if (should_add_something) path += "something";
234+
return path;
235+
}
236+
```
227237

228-
// custom rewriting, returning Promise
229-
pathRewrite: async function (path, req) {
230-
const should_add_something = await httpRequestToDecideSomething(path);
231-
if (should_add_something) path += "something";
232-
return path;
233-
}
234-
```
238+
### `router` (object/function)
235239

236-
- **option.router**: object/function, re-target `option.target` for specific requests.
240+
Re-target `option.target` for specific requests.
237241

238-
```javascript
239-
// Use `host` and/or `path` to match requests. First match will be used.
240-
// The order of the configuration matters.
241-
router: {
242-
'integration.localhost:3000' : 'http://localhost:8001', // host only
243-
'staging.localhost:3000' : 'http://localhost:8002', // host only
244-
'localhost:3000/api' : 'http://localhost:8003', // host + path
245-
'/rest' : 'http://localhost:8004' // path only
246-
}
242+
```javascript
243+
// Use `host` and/or `path` to match requests. First match will be used.
244+
// The order of the configuration matters.
245+
router: {
246+
'integration.localhost:3000' : 'http://localhost:8001', // host only
247+
'staging.localhost:3000' : 'http://localhost:8002', // host only
248+
'localhost:3000/api' : 'http://localhost:8003', // host + path
249+
'/rest' : 'http://localhost:8004' // path only
250+
}
251+
252+
// Custom router function (string target)
253+
router: function(req) {
254+
return 'http://localhost:8004';
255+
}
256+
257+
// Custom router function (target object)
258+
router: function(req) {
259+
return {
260+
protocol: 'https:', // The : is required
261+
host: 'localhost',
262+
port: 8004
263+
};
264+
}
247265

248-
// Custom router function (string target)
249-
router: function(req) {
250-
return 'http://localhost:8004';
251-
}
266+
// Asynchronous router function which returns promise
267+
router: async function(req) {
268+
const url = await doSomeIO();
269+
return url;
270+
}
271+
```
252272

253-
// Custom router function (target object)
254-
router: function(req) {
255-
return {
256-
protocol: 'https:', // The : is required
257-
host: 'localhost',
258-
port: 8004
259-
};
260-
}
273+
### `logLevel` (string)
261274

262-
// Asynchronous router function which returns promise
263-
router: async function(req) {
264-
const url = await doSomeIO();
265-
return url;
266-
}
267-
```
275+
Default: `'info'`
268276

269-
- **option.logLevel**: string, ['debug', 'info', 'warn', 'error', 'silent']. Default: `'info'`
277+
Values: ['debug', 'info', 'warn', 'error', 'silent'].
270278

271-
- **option.logProvider**: function, modify or replace log provider. Default: `console`.
279+
### `logProvider` (function)
272280

273-
```javascript
274-
// simple replace
275-
function logProvider(provider) {
276-
// replace the default console log provider.
277-
return require('winston');
278-
}
279-
```
281+
Modify or replace log provider. Default: `console`.
280282

281-
```javascript
282-
// verbose replacement
283-
function logProvider(provider) {
284-
const logger = new (require('winston').Logger)();
285-
286-
const myCustomProvider = {
287-
log: logger.log,
288-
debug: logger.debug,
289-
info: logger.info,
290-
warn: logger.warn,
291-
error: logger.error,
292-
};
293-
return myCustomProvider;
294-
}
295-
```
283+
```javascript
284+
// simple replace
285+
function logProvider(provider) {
286+
// replace the default console log provider.
287+
return require('winston');
288+
}
289+
```
290+
291+
```javascript
292+
// verbose replacement
293+
function logProvider(provider) {
294+
const logger = new (require('winston').Logger)();
295+
296+
const myCustomProvider = {
297+
log: logger.log,
298+
debug: logger.debug,
299+
info: logger.info,
300+
warn: logger.warn,
301+
error: logger.error,
302+
};
303+
return myCustomProvider;
304+
}
305+
```
296306

297-
### http-proxy events
307+
## `http-proxy` events
298308

299309
Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events):
300310

@@ -355,7 +365,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
355365
}
356366
```
357367

358-
### http-proxy options
368+
## `http-proxy` options
359369

360370
The following options are provided by the underlying [http-proxy](https://github.com/nodejitsu/node-http-proxy#options) library.
361371

@@ -431,15 +441,15 @@ The following options are provided by the underlying [http-proxy](https://github
431441

432442
```javascript
433443
// verbose api
434-
createProxyMiddleware('/', { target: 'http://echo.websocket.org', ws: true });
444+
createProxyMiddleware({ pathFilter: '/', target: 'http://echo.websocket.org', ws: true });
435445
```
436446

437447
### External WebSocket upgrade
438448

439449
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.
440450

441451
```javascript
442-
const wsProxy = createProxyMiddleware('ws://echo.websocket.org', { changeOrigin: true });
452+
const wsProxy = createProxyMiddleware({ target: 'ws://echo.websocket.org', changeOrigin: true });
443453

444454
const app = express();
445455
app.use(wsProxy);

examples/browser-sync/index.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,9 @@ const { createProxyMiddleware } = require('../../dist'); // require('http-proxy-
77
/**
88
* Configure proxy middleware
99
*/
10-
const jsonPlaceholderProxy = createProxyMiddleware('/users', {
10+
const jsonPlaceholderProxy = createProxyMiddleware({
1111
target: 'http://jsonplaceholder.typicode.com',
12+
pathFilter: '/users',
1213
changeOrigin: true, // for vhosted sites, changes host header to match to target's host
1314
logLevel: 'debug',
1415
});

examples/websocket/index.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<body>
2222
<h2>WebSocket demo</h2>
2323

24-
<p>Proxy <code>ws://localhost:3000</code> to <code>ws://echo.websocket.org</code></p>
24+
<p>Proxy <code>ws://localhost:3000</code> to <code>ws://ws.ifelse.io</code></p>
2525

2626
<fieldset id="configuration">
2727
<p>

examples/websocket/index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ const { createProxyMiddleware } = require('../../dist'); // require('http-proxy-
77
/**
88
* Configure proxy middleware
99
*/
10-
const wsProxy = createProxyMiddleware('/', {
11-
target: 'http://echo.websocket.org',
10+
const wsProxy = createProxyMiddleware({
11+
target: 'http://ws.ifelse.io',
1212
// pathRewrite: {
1313
// '^/websocket' : '/socket', // rewrite path.
1414
// '^/removepath' : '' // remove path.

0 commit comments

Comments
 (0)