Skip to content

Commit 6312ad9

Browse files
committed
feat(option): refactor context to pathFilter option [BREAKING CHANGE] (#722)
1 parent 598361e commit 6312ad9

22 files changed

+558
-609
lines changed

README.md

+124-110
Original file line numberDiff line numberDiff line change
@@ -54,15 +54,20 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
5454

5555
## Table of Contents <!-- omit in toc -->
5656

57+
<!-- // spell-checker:disable -->
58+
5759
- [Install](#install)
5860
- [Core concept](#core-concept)
59-
- [Example](#example)
61+
- [Express Server Example](#express-server-example)
6062
- [app.use(path, proxy)](#appusepath-proxy)
61-
- [Context matching](#context-matching)
6263
- [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)
64+
- [`pathFilter` (string, []string, glob, []glob, function)](#pathfilter-string-string-glob-glob-function)
65+
- [`pathRewrite` (object/function)](#pathrewrite-objectfunction)
66+
- [`router` (object/function)](#router-objectfunction)
67+
- [`logLevel` (string)](#loglevel-string)
68+
- [`logProvider` (function)](#logprovider-function)
69+
- [`http-proxy` events](#http-proxy-events)
70+
- [`http-proxy` options](#http-proxy-options)
6671
- [WebSocket](#websocket)
6772
- [External WebSocket upgrade](#external-websocket-upgrade)
6873
- [Intercept and manipulate requests](#intercept-and-manipulate-requests)
@@ -74,36 +79,36 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
7479
- [Changelog](#changelog)
7580
- [License](#license)
7681

82+
<!-- // spell-checker:enable -->
83+
7784
## Install
7885

79-
```bash
80-
$ npm install --save-dev http-proxy-middleware
86+
```shell
87+
npm install --save-dev http-proxy-middleware
8188
```
8289

8390
## Core concept
8491

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

8994
```javascript
9095
const { createProxyMiddleware } = require('http-proxy-middleware');
9196

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

97102
// 'apiProxy' is now ready to be used as middleware in a server.
98103
```
99104

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

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

106-
## Example
111+
## Express Server Example
107112

108113
An example with `express` server.
109114

@@ -129,7 +134,7 @@ const options = {
129134
},
130135
};
131136

132-
// create the proxy (without context)
137+
// create the proxy
133138
const exampleProxy = createProxyMiddleware(options);
134139

135140
// mount `exampleProxy` in web server
@@ -140,8 +145,8 @@ app.listen(3000);
140145

141146
### app.use(path, proxy)
142147

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:
148+
If you want to use the server's `app.use` `path` parameter to match requests.
149+
Use `pathFilter` option to further include/exclude requests which you want to proxy.
145150

146151
```javascript
147152
app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true }));
@@ -153,11 +158,15 @@ app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', change
153158
- connect: https://github.com/senchalabs/connect#mount-middleware
154159
- polka: https://github.com/lukeed/polka#usebase-fn
155160

156-
## Context matching
161+
## Options
162+
163+
http-proxy-middleware options:
164+
165+
### `pathFilter` (string, []string, glob, []glob, function)
157166

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.
167+
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.
159168

160-
[RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used for context matching.
169+
[RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used in `pathFilter`.
161170

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

171180
- `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`
181+
- `createProxyMiddleware({ pathFilter: '/api', ...})` - matches paths starting with `/api`
174182

175183
- **multiple path matching**
176184

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

179187
- **wildcard path matching**
180188

181189
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.
182190

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
191+
- `createProxyMiddleware({ pathFilter: '**', ...})` matches any path, all requests will be proxied.
192+
- `createProxyMiddleware({ pathFilter: '**/*.html', ...})` matches any path which ends with `.html`
193+
- `createProxyMiddleware({ pathFilter: '/*.html', ...})` matches paths directly under path-absolute
194+
- `createProxyMiddleware({ pathFilter: '/api/**/*.html', ...})` matches requests ending with `.html` in the path of `/api`
195+
- `createProxyMiddleware({ pathFilter: ['/api/**', '/ajax/**'], ...})` combine multiple patterns
196+
- `createProxyMiddleware({ pathFilter: ['/api/**', '!**/bad.json'], ...})` exclusion
189197

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

@@ -197,104 +205,110 @@ Providing an alternative way to decide which requests should be proxied; In case
197205
/**
198206
* @return {Boolean}
199207
*/
200-
const filter = function (pathname, req) {
201-
return pathname.match('^/api') && req.method === 'GET';
208+
const filter = function (path, req) {
209+
return path.match('^/api') && req.method === 'GET';
202210
};
203211

204212
const apiProxy = createProxyMiddleware(filter, {
205213
target: 'http://www.example.org',
206214
});
207215
```
208216

209-
## Options
217+
### `pathRewrite` (object/function)
210218

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

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

215-
```javascript
216-
// rewrite path
217-
pathRewrite: {'^/old/api' : '/new/api'}
225+
// remove path
226+
pathRewrite: {'^/remove/api' : ''}
218227

219-
// remove path
220-
pathRewrite: {'^/remove/api' : ''}
228+
// add base path
229+
pathRewrite: {'^/' : '/basepath/'}
221230

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

225-
// custom rewriting
226-
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }
234+
// custom rewriting, returning Promise
235+
pathRewrite: async function (path, req) {
236+
const should_add_something = await httpRequestToDecideSomething(path);
237+
if (should_add_something) path += "something";
238+
return path;
239+
}
240+
```
227241

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-
```
242+
### `router` (object/function)
235243

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

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-
}
246+
```javascript
247+
// Use `host` and/or `path` to match requests. First match will be used.
248+
// The order of the configuration matters.
249+
router: {
250+
'integration.localhost:3000' : 'http://localhost:8001', // host only
251+
'staging.localhost:3000' : 'http://localhost:8002', // host only
252+
'localhost:3000/api' : 'http://localhost:8003', // host + path
253+
'/rest' : 'http://localhost:8004' // path only
254+
}
255+
256+
// Custom router function (string target)
257+
router: function(req) {
258+
return 'http://localhost:8004';
259+
}
260+
261+
// Custom router function (target object)
262+
router: function(req) {
263+
return {
264+
protocol: 'https:', // The : is required
265+
host: 'localhost',
266+
port: 8004
267+
};
268+
}
247269

248-
// Custom router function (string target)
249-
router: function(req) {
250-
return 'http://localhost:8004';
251-
}
270+
// Asynchronous router function which returns promise
271+
router: async function(req) {
272+
const url = await doSomeIO();
273+
return url;
274+
}
275+
```
252276

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-
}
277+
### `logLevel` (string)
261278

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

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

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

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

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-
```
287+
```javascript
288+
// simple replace
289+
function logProvider(provider) {
290+
// replace the default console log provider.
291+
return require('winston');
292+
}
293+
```
294+
295+
```javascript
296+
// verbose replacement
297+
function logProvider(provider) {
298+
const logger = new (require('winston').Logger)();
299+
300+
const myCustomProvider = {
301+
log: logger.log,
302+
debug: logger.debug,
303+
info: logger.info,
304+
warn: logger.warn,
305+
error: logger.error,
306+
};
307+
return myCustomProvider;
308+
}
309+
```
296310

297-
### http-proxy events
311+
## `http-proxy` events
298312

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

@@ -355,7 +369,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
355369
}
356370
```
357371

358-
### http-proxy options
372+
## `http-proxy` options
359373

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

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

432446
```javascript
433447
// verbose api
434-
createProxyMiddleware('/', { target: 'http://echo.websocket.org', ws: true });
448+
createProxyMiddleware({ pathFilter: '/', target: 'http://echo.websocket.org', ws: true });
435449
```
436450

437451
### External WebSocket upgrade
438452

439453
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.
440454

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

444458
const app = express();
445459
app.use(wsProxy);

examples/browser-sync/index.js

+2-1
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

+1-1
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

+2-2
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)