Skip to content

Commit ea41a26

Browse files
committed
Merge pull request #59 from chimurai/custom-context-matching
feat(context): custom context matcher
2 parents 483f757 + 814e0fc commit ea41a26

11 files changed

+352
-213
lines changed

README.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ Request URL's [ _path-absolute_ and _query_](https://tools.ietf.org/html/rfc3986
9494
- `['/api', '/ajax', '/someotherpath']`
9595

9696
* **wildcard path matching**
97+
9798
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.
9899
- `'**'` matches any path, all requests will be proxied.
99100
- `'**/*.html'` matches any path which ends with `.html`
@@ -102,6 +103,17 @@ Request URL's [ _path-absolute_ and _query_](https://tools.ietf.org/html/rfc3986
102103
- `['/api/**', '/ajax/**']` combine multiple patterns
103104
- `['/api/**', '!**/bad.json']` exclusion
104105

106+
* **custom matching**
107+
108+
For full control you can provide a custom filter function to determine which requests should be proxied or not.
109+
```javascript
110+
var filter = function (path, req) {
111+
return (path.match('^/api') && req.method === 'GET');
112+
};
113+
114+
var apiProxy = proxyMiddleware(filter, {target: 'http://www.example.org'})
115+
```
116+
105117
## Shorthand
106118

107119
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.

index.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ var httpProxyMiddleware = function(context, opts) {
3939
req.url = req.originalUrl;
4040
}
4141

42-
if (contextMatcher.match(config.context, req.url)) {
42+
if (contextMatcher.match(config.context, req.url, req)) {
4343
var activeProxyOptions = prepareProxyRequest(req);
4444
proxy.web(req, res, activeProxyOptions);
4545
} else {
@@ -62,7 +62,7 @@ var httpProxyMiddleware = function(context, opts) {
6262
}
6363

6464
function handleUpgrade(req, socket, head) {
65-
if (contextMatcher.match(config.context, req.url)) {
65+
if (contextMatcher.match(config.context, req.url, req)) {
6666
var activeProxyOptions = prepareProxyRequest(req);
6767
proxy.ws(req, socket, head, activeProxyOptions);
6868
logger.info('[HPM] Upgrading to WebSocket');

lib/context-matcher.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
var _ = require('lodash');
12
var url = require('url');
23
var isGlob = require('is-glob');
34
var micromatch = require('micromatch');
@@ -6,15 +7,18 @@ module.exports = {
67
match: matchContext
78
};
89

9-
function matchContext(context, uri) {
10+
function matchContext(context, uri, req) {
11+
1012
// single path
1113
if (isStringPath(context)) {
1214
return matchSingleStringPath(context, uri);
1315
}
16+
1417
// single glob path
1518
if (isGlobPath(context)) {
1619
return matchSingleGlobPath(context, uri);
1720
}
21+
1822
// multi path
1923
if (Array.isArray(context)) {
2024
if (context.every(isStringPath)) {
@@ -27,6 +31,12 @@ function matchContext(context, uri) {
2731
throw new Error('[HPM] Invalid context. Expecting something like: ["/api", "/ajax"] or ["/api/**", "!**.html"]');
2832
}
2933

34+
// custom matching
35+
if (_.isFunction(context)) {
36+
var path = getUrlPath(uri);
37+
return context(path, req);
38+
}
39+
3040
throw new Error('[HPM] Invalid context. Expecting something like: "/api" or ["/api", "/ajax"]');
3141
}
3242

@@ -70,7 +80,7 @@ function getUrlPath(uri) {
7080
}
7181

7282
function isStringPath(context) {
73-
return typeof context === 'string' && !isGlob(context);
83+
return _.isString(context) && !isGlob(context);
7484
}
7585

7686
function isGlobPath(context) {

recipes/context.md

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
# Context matching
2+
3+
## Path
4+
5+
This example will create a basic proxy.
6+
7+
Requests with path `/api` will be proxied to `http://localhost:3000`
8+
9+
```javascript
10+
var proxy = require("http-proxy-middleware");
11+
12+
var apiProxy = proxy('/api', {target: 'http://localhost:3000'});
13+
14+
// `/api/foo/bar` -> `http://localhost:3000/api/foo/bar`
15+
```
16+
17+
## Multi Path
18+
19+
This example will create a basic proxy
20+
21+
Requests with path `/api` and `/rest` will be proxied to `http://localhost:3000`
22+
23+
```javascript
24+
var proxy = require("http-proxy-middleware");
25+
26+
var apiProxy = proxy(['/api', '/rest'], {target: 'http://localhost:3000'});
27+
28+
// `/api/foo/bar` -> `http://localhost:3000/api/foo/bar`
29+
// `/rest/lorum/ipsum` -> `http://localhost:3000/rest/lorum/ipsum`
30+
```
31+
32+
## Wildcard
33+
34+
This example will create a proxy with wildcard context matching.
35+
36+
```javascript
37+
var proxy = require("http-proxy-middleware");
38+
39+
var apiProxy = proxy('/api/**/*.json', {target: 'http://localhost:3000'});
40+
```
41+
42+
## Multi Wildcard
43+
44+
This example will create a proxy with wildcard context matching.
45+
46+
```javascript
47+
var proxy = require("http-proxy-middleware");
48+
49+
var apiProxy = proxy(['/api/**', '/ajax/**'], {target: 'http://localhost:3000'});
50+
```
51+
52+
## Wildcard / Exclusion
53+
54+
This example will create a proxy with wildcard context matching.
55+
56+
```javascript
57+
var proxy = require("http-proxy-middleware");
58+
59+
var apiProxy = proxy(['/api/**', '!**/bad.json'], {target: 'http://localhost:3000'});
60+
```
61+
62+
## Custom filtering
63+
64+
This example will create a proxy with custom filtering.
65+
The request `path` and `req` object are provided to determine which requests should be proxied or not.
66+
67+
```javascript
68+
var proxy = require("http-proxy-middleware");
69+
70+
var filter = function (path, req) {
71+
return (path.match('^/api') && req.method === 'GET');
72+
};
73+
74+
var apiProxy = proxy(filter, {target: 'http://localhost:3000'});
75+
```

recipes/context.path.md

Lines changed: 0 additions & 13 deletions
This file was deleted.

recipes/context.path.multi.md

Lines changed: 0 additions & 14 deletions
This file was deleted.

recipes/context.wildcard.exclusion.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

recipes/context.wildcard.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

recipes/context.wildcard.multi.md

Lines changed: 0 additions & 9 deletions
This file was deleted.

0 commit comments

Comments
 (0)