http-proxy-middleware
Advanced tools
Comparing version 0.4.0 to 0.5.0
37
index.js
@@ -9,3 +9,2 @@ var httpProxy = require('http-proxy'); | ||
var proxyOptions = opts || {}; | ||
var pathRewriter; | ||
@@ -29,15 +28,22 @@ // Legacy option.proxyHost | ||
pathRewriter = PathRewriter.create(proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided | ||
var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided | ||
// handle option.pathRewrite | ||
if (pathRewriter) { | ||
proxy.on('proxyReq', function (proxyReq, req, res, options) { | ||
var proxyReqPathRewrite = function (proxyReq, req, res, options) { | ||
proxyReq.path = pathRewriter(proxyReq.path); | ||
}); | ||
}; | ||
proxy.on('proxyReq', proxyReqPathRewrite); | ||
} | ||
// Custom listener for the `proxyRes` event on `proxy`. | ||
if (isFunction(proxyOptions.onProxyRes)) { | ||
proxy.on('proxyRes', proxyOptions.onProxyRes); | ||
} | ||
// Custom listener for the `error` event on `proxy`. | ||
var onProxyError = getProxyErrorHandler(); | ||
// handle error and close connection properly | ||
proxy.on('error', function (err, req, res) { | ||
handlers.proxyError(err, req, res, proxyOptions); | ||
}); | ||
proxy.on('error', onProxyError); | ||
proxy.on('error', proxyErrorLogger); | ||
@@ -83,4 +89,21 @@ // Listen for the `close` event on `proxy`. | ||
function getProxyErrorHandler () { | ||
if (isFunction(proxyOptions.onError)) { | ||
return proxyOptions.onError; // custom error listener | ||
} | ||
return handlers.proxyError; // otherwise fall back to default | ||
} | ||
function proxyErrorLogger (err, req, res) { | ||
var targetUri = proxyOptions.target.host + req.url; | ||
console.log('[HPM] Proxy error:', err.code, targetUri); | ||
} | ||
function isFunction (v) { | ||
return (v && typeof v === 'function'); | ||
} | ||
}; | ||
module.exports = httpProxyMiddleware; |
@@ -5,9 +5,6 @@ module.exports = { | ||
function proxyError (err, req, res, proxyOptions) { | ||
var targetUri = proxyOptions.target.host + req.url; | ||
function proxyError (err, req, res) { | ||
var host = (req.headers && req.headers.host) || ''; | ||
res.writeHead(500); | ||
res.end('Error occured while trying to proxy to: '+ proxyOptions.target.host + req.url); | ||
console.log('[HPM] Proxy error:', err.code, targetUri); | ||
res.end('Error occured while trying to proxy to: '+ host + req.url); | ||
}; |
{ | ||
"name": "http-proxy-middleware", | ||
"version": "0.4.0", | ||
"description": "The one-liner proxy middleware for connect, express and browser-sync", | ||
"version": "0.5.0", | ||
"description": "The one-liner node.js proxy middleware for connect, express and browser-sync", | ||
"main": "index.js", | ||
@@ -6,0 +6,0 @@ "scripts": { |
@@ -7,3 +7,3 @@ # http-proxy-middleware | ||
The one-liner proxy middleware for [connect](https://github.com/senchalabs/connect), [express](https://github.com/strongloop/express) and [browser-sync](https://github.com/BrowserSync/browser-sync) | ||
The one-liner node.js proxy middleware for [connect](https://github.com/senchalabs/connect), [express](https://github.com/strongloop/express) and [browser-sync](https://github.com/BrowserSync/browser-sync) | ||
@@ -32,3 +32,3 @@ ### Install | ||
* **options.target**: target host to proxy to. | ||
Check out available [proxy options](#options). | ||
Check out available [proxy middleware options](#options). | ||
@@ -48,3 +48,7 @@ | ||
target: 'http://www.example.org', // target host | ||
changeOrigin: true // needed for virtual hosted sites | ||
changeOrigin: true, // needed for virtual hosted sites | ||
ws: true, // proxy websockets | ||
pathRewrite: { | ||
'^/old/api' : '/new/api' // rewrite paths | ||
} | ||
}; | ||
@@ -61,6 +65,27 @@ | ||
See [more examples](#more-examples). | ||
See [working examples](#more-examples). | ||
**Tip:** For [name-based virtual hosted sites](http://en.wikipedia.org/wiki/Virtual_hosting#Name-based), you'll need to use the option `changeOrigin` and set it to `true`. | ||
### Context matching | ||
http-proxy-middleware offers several ways to decide which requests should be proxied. | ||
Request URL's [ _path-absolute_ and _query_](https://tools.ietf.org/html/rfc3986#section-3) will be used for context matching . | ||
* path matching | ||
* `'/'` - matches any path, all requests will be proxied. | ||
* `'/api'` - matches paths starting with `/api` | ||
* multiple path matching | ||
* `['/api','/ajax','/someotherpath']` | ||
* wildcard path matching | ||
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. | ||
* `**` matches any path, all requests will be proxied. | ||
* `**/*.html` matches any path which ends with `.html` | ||
* `/*.html` matches paths directly under path-absolute | ||
* `/api/**/*.html` matches requests ending with `.html` in the path of `/api` | ||
* `['/api/**', '/ajax/**']` combine multiple patterns | ||
* `['/api/**', '!**/bad.json']` exclusion | ||
### Compatible servers: | ||
@@ -74,6 +99,3 @@ http-proxy-middleware is compatible with the following servers: | ||
### Options | ||
* (DEPRECATED) **option.proxyHost**: Use `option.changeOrigin = true` instead. | ||
* **option.pathRewrite**: object, rewrite target's url path. Object-keys will be used as _RegExp_ to match paths. | ||
```javascript | ||
@@ -86,2 +108,21 @@ { | ||
* **option.onError**: function, subscribe to http-proxy's error event for custom error handling. | ||
```javascript | ||
function onError (err, req, res) { | ||
res.writeHead(500, { | ||
'Content-Type': 'text/plain' | ||
}); | ||
res.end('Something went wrong. And we are reporting a custom error message.'); | ||
} | ||
``` | ||
* **option.onProxyRes**: function, subscribe to http-proxy's proxyRes event. | ||
```javascript | ||
function (proxyRes, req, res) { | ||
proxyRes.headers['x-added'] = 'foobar'; // add new header to response | ||
delete proxyRes.headers['x-removed']; // remove header from response | ||
} | ||
``` | ||
* (DEPRECATED) **option.proxyHost**: Use `option.changeOrigin = true` instead. | ||
The following options are provided by the underlying [http-proxy](https://www.npmjs.com/package/http-proxy). | ||
@@ -95,3 +136,3 @@ * **option.target**: url string to be parsed with the url module | ||
* **option.hostRewrite**: rewrites the location hostname on (301/302/307/308) redirects. | ||
* **option.ssl: object to be passed to https.createServer() | ||
* **option.ssl**: object to be passed to https.createServer() | ||
* **option.ws: true/false**: if you want to proxy websockets | ||
@@ -110,24 +151,2 @@ | ||
### Context matching | ||
Request URL's [ _path-absolute_ and _query_](https://tools.ietf.org/html/rfc3986#section-3) will be used for context matching . | ||
* URL: `http://example.com:8042/over/there?name=ferret#nose` | ||
* context: `/over/there?name=ferret` | ||
http-proxy-middleware offers several ways to decide which requests should be proxied: | ||
* path matching | ||
* `'/'` - matches any path, all requests will be proxied. | ||
* `'/api'` - matches paths starting with `/api` | ||
* multiple path matching | ||
* `['/api','/ajax','/someotherpath']` | ||
* wildcard path matching | ||
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. | ||
* `**` matches any path, all requests will be proxied. | ||
* `**/*.html` matches any path which ends with `.html` | ||
* `/*.html` matches paths directly under path-absolute | ||
* `/api/**/*.html` matches requests ending with `.html` in the path of `/api` | ||
* `['/api/**', '/ajax/**']` combine multiple patterns | ||
* `['/api/**', '!**/bad.json']` exclusion | ||
### More Examples | ||
@@ -150,6 +169,6 @@ | ||
Or just explore the proxy examples' sources: | ||
* `examples/connect` - [connect proxy middleware example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/connect) | ||
* `examples/express` - [express proxy middleware example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/express) | ||
* `examples/browser-sync` - [browser-sync proxy middleware example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/browser-sync) | ||
* `examples/websocket` - [websocket proxy example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/websocket) with express | ||
* `examples/connect` - [connect proxy middleware example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/connect/index.js) | ||
* `examples/express` - [express proxy middleware example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/express/index.js) | ||
* `examples/browser-sync` - [browser-sync proxy middleware example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/browser-sync/index.js) | ||
* `examples/websocket` - [websocket proxy example](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/websocket/index.js) with express | ||
@@ -169,2 +188,3 @@ ### Tests | ||
### Changlog | ||
* [v0.5.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.5.0) - support subscribing to http-proxy error- and proxyRes-event | ||
* [v0.4.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.4.0) - support websocket | ||
@@ -171,0 +191,0 @@ * [v0.3.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v0.3.0) - support wildcard / glob |
@@ -9,2 +9,7 @@ var expect = require('chai').expect; | ||
it('should match all paths', function () { | ||
result = contextMatcher.match('', 'http://localhost/api/foo/bar'); | ||
expect(result).to.be.true; | ||
}); | ||
it('should match all paths starting with forward-slash', function () { | ||
result = contextMatcher.match('/', 'http://localhost/api/foo/bar'); | ||
@@ -11,0 +16,0 @@ expect(result).to.be.true; |
@@ -11,2 +11,5 @@ var expect = require('chai').expect; | ||
var mockReq = { | ||
headers : { | ||
host : 'localhost:3000' | ||
}, | ||
url : '/api' | ||
@@ -43,5 +46,5 @@ }; | ||
it('should end the response and return error message', function () { | ||
expect(errorMessage).to.equal('Error occured while trying to proxy to: localhost.dev/api'); | ||
expect(errorMessage).to.equal('Error occured while trying to proxy to: localhost:3000/api'); | ||
}); | ||
}); |
@@ -255,3 +255,3 @@ var expect = require('chai').expect; | ||
describe('additional request headers', function () { | ||
describe('option.headers - additional request headers', function () { | ||
var proxyServer, targetServer; | ||
@@ -286,3 +286,3 @@ var targetHeaders; | ||
describe('legacy proxyHost parameter', function () { | ||
describe('legacy option.proxyHost', function () { | ||
var proxyServer, targetServer; | ||
@@ -318,16 +318,96 @@ var targetHeaders; | ||
describe('Error handling', function () { | ||
describe('option.onError - Error handling', function () { | ||
var proxyServer, targetServer; | ||
var response; | ||
var response, responseBody; | ||
describe('default', function () { | ||
beforeEach(function (done) { | ||
var mw_proxy = proxyMiddleware('/api', {target:'http://localhost:666'}); // unreachable host on port:666 | ||
var mw_target = function (req, res, next) {next()}; | ||
proxyServer = createServer(3000, mw_proxy); | ||
targetServer = createServer(8000, mw_target); | ||
http.get('http://localhost:3000/api/', function (res) { | ||
response = res; | ||
done(); | ||
}); | ||
}); | ||
afterEach(function () { | ||
proxyServer.close(); | ||
targetServer.close(); | ||
}); | ||
it('should handle errors when host is not reachable', function () { | ||
expect(response.statusCode).to.equal(500); | ||
}); | ||
}); | ||
describe('custom', function () { | ||
beforeEach(function (done) { | ||
var customOnError = function (err, req, res) { | ||
res.writeHead(418); // different error code | ||
res.end("I'm a teapot"); // no response body | ||
}; | ||
var mw_proxy = proxyMiddleware('/api', {target:'http://localhost:666', onError: customOnError}); // unreachable host on port:666 | ||
var mw_target = function (req, res, next) {next()}; | ||
proxyServer = createServer(3000, mw_proxy); | ||
targetServer = createServer(8000, mw_target); | ||
http.get('http://localhost:3000/api/', function (res) { | ||
response = res; | ||
res.on('data', function (chunk) { | ||
responseBody = chunk.toString(); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
afterEach(function () { | ||
proxyServer.close(); | ||
targetServer.close(); | ||
}); | ||
it('should respond with custom http status code', function () { | ||
expect(response.statusCode).to.equal(418); | ||
}); | ||
it('should respond with custom status message', function () { | ||
expect(responseBody).to.equal("I'm a teapot"); | ||
}); | ||
}); | ||
}); | ||
describe('option.onProxyRes', function () { | ||
var proxyServer, targetServer; | ||
var response, responseBody; | ||
beforeEach(function (done) { | ||
var mw_proxy = proxyMiddleware('/api', {target:'http://localhost:666'}); // unreachable host on port:666 | ||
var mw_target = function (req, res, next) {next()}; | ||
var fnOnProxyRes = function (proxyRes, req, res) { | ||
proxyRes.headers['x-added'] = 'foobar'; // add custom header to response | ||
delete proxyRes.headers['x-removed']; | ||
}; | ||
var mw_proxy = proxyMiddleware('/api', { | ||
target:'http://localhost:8000', | ||
onProxyRes: fnOnProxyRes | ||
}); | ||
var mw_target = function (req, res, next) { | ||
res.setHeader('x-removed', 'remove-header'); | ||
res.write(req.url); // respond with req.url | ||
res.end(); | ||
}; | ||
proxyServer = createServer(3000, mw_proxy); | ||
targetServer = createServer(8000, mw_target); | ||
http.get('http://localhost:3000/api/', function (res) { | ||
http.get('http://localhost:3000/api/foo/bar', function (res) { | ||
response = res; | ||
done(); | ||
res.on('data', function (chunk) { | ||
responseBody = chunk.toString(); | ||
done(); | ||
}); | ||
}); | ||
@@ -341,9 +421,12 @@ }); | ||
it('should add `x-added` as custom header to response"', function () { | ||
expect(response.headers['x-added']).to.equal('foobar'); | ||
}); | ||
it('should handle errors when host is not reachable', function () { | ||
expect(response.statusCode).to.equal(500); | ||
it('should remove `x-removed` field from response header"', function () { | ||
expect(response.headers['x-removed']).to.equal(undefined); | ||
}); | ||
}); | ||
describe('Rewrite path', function () { | ||
describe('option.pathRewrite', function () { | ||
var proxyServer, targetServer; | ||
@@ -350,0 +433,0 @@ var responseBody; |
@@ -8,3 +8,3 @@ var expect = require('chai').expect; | ||
describe('websocket proxy', function () { | ||
describe('option.ws - WebSocket proxy', function () { | ||
var proxyServer, ws, wss; | ||
@@ -11,0 +11,0 @@ var targetHeaders; |
56081
1008
209