Proxy middleware for express/connect
Express middleware to proxy request to another host and pass response back to original caller.
$ npm install express-http-proxy --saveproxy(host, options);To proxy URLS starting with '/proxy' to the host 'www.google.com':
var proxy = require('express-http-proxy');
var app = require('express')();
app.use('/proxy', proxy('www.google.com'));The proxy middleware:
…In this example, when memoizeHost:false, the coinToss occurs on each
request, and each request could get either value.
Conversely, When memoizeHost:true, the coinToss would occur on the first
request, and all additional requests would return the value resolved on the
first request.
When a userResHeaderDecorator is defined, the return of this method will replace (rather than be merged on to) the headers for userRes.
Note that by default, headers from the PROXY response CLOBBER all headers that may have previously been set on the userResponse. Authors have the option of constructing any combination of proxyRes and userRes headers in the
userResHeaderDecorator. Check the tests for this method for examples.
app.use('/proxy', proxy('www.google.com', {
userResHeaderDecorator(headers, userReq, userRes, proxyReq, proxyRes) {
// recieves an Object of headers, returns an Object of headers.
return headers;
}
}));REMOVED: See proxyReqOptDecorator and proxyReqBodyDecorator.
(experimental: this interface may change in upcoming versions)
Allows you to inspect the proxy response, and decide if you want to continue processing (via express-http-proxy) or call next() to return control to express.
app.use('/proxy', proxy('www.google.com', {
skipToNextHandlerFilter: function(proxyRes) {
return proxyRes.statusCode === 404;
}
}));By default, express-http-proxy will pass any errors except ECONNRESET to
next, so that your application can handle or react to them, or just drop
through to your default error handling. ECONNRESET errors are immediately
returned to the user for historical reasons.
If you would like to modify this behavior, you can provide your own proxyErrorHandler.
// Example of skipping all error handling.
app.use(proxy('localhost:12346', {
proxyErrorHandler: function(err, res, next) {
next(err);
}
}));
// Example of rolling your own
app.use(proxy('localhost:12346', {
proxyErrorHandler: function(err, res, next) {
switch (err && err.code) {
case 'ECONNRESET': { return res.status(405).send('504 became 405'); }
case 'ECONNREFUSED': { return res.status(200).send('gotcher back'); }
default: { next(err); }
}
}}));You can override most request options before issuing the proxyRequest. proxyReqOpt represents the options argument passed to the (http|https).request module.
NOTE: req.path cannot be changed via this method; use proxyReqPathResolver instead. (see https://github.com/villadora/express-http-proxy/issues/243)
app.use('/proxy', proxy('www.google.com', {
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
// you can update headers
proxyReqOpts.headers['Content-Type'] = 'text/html';
// you can change the method
proxyReqOpts.method = 'GET';
return proxyReqOpts;
}
}));You can use a Promise for async style.
app.use('/proxy', proxy('www.google.com', {
proxyReqOptDecorator: function(proxyReqOpts, srcReq) {
return new Promise(function(resolve, reject) {
proxyReqOpts.headers['Content-Type'] = 'text/html';
resolve(proxyReqOpts);
})
}
}));You can mutate the body content before sending the proxyRequest.
app.use('/proxy', proxy('www.google.com', {
proxyReqBodyDecorator: function(bodyContent, srcReq) {
return bodyContent.split('').reverse().join('');
}
}));You can use a Promise for async style.
app.use('/proxy', proxy('www.google.com', {
proxyReqBodyDecorator: function(proxyReq, srcReq) {
return new Promise(function(resolve, reject) {
http.get('http://dev/null', function (err, res) {
if (err) { reject(err); }
resolve(res);
});
})
}
}));Normally, your proxy request will be made on the same protocol as the host
parameter. If you'd like to force the proxy request to be https, use this
option.
app.use('/proxy', proxy('www.google.com', {
https: true
}));You can copy the host HTTP header to the proxied express server using the preserveHostHdr option.
app.use('/proxy', proxy('www.google.com', {
preserveHostHdr: true
}));The parseReqBody option allows you to control parsing the request body.
For example, disabling body parsing is useful for large uploads where it would be inefficient
to hold the data in memory.
This defaults to true in order to preserve legacy behavior.
When false, no action will be taken on the body and accordingly req.body will no longer be set.
Note that setting this to false overrides reqAsBuffer and reqBodyEncoding below.
app.use('/proxy', proxy('www.google.com', {
parseReqBody: false
}));Note: this is an experimental feature. ymmv
The reqAsBuffer option allows you to ensure the req body is encoded as a Node
Buffer when sending a proxied request. Any value for this is truthy.
This defaults to to false in order to preserve legacy behavior. Note that
the value of reqBodyEnconding is used as the encoding when coercing strings
(and stringified JSON) to Buffer.
Ignored if parseReqBody is set to false.
app.use('/proxy', proxy('www.google.com', {
reqAsBuffer: true
}));Encoding used to decode request body. Defaults to utf-8.
Use null to preserve as Buffer when proxied request body is a Buffer. (e.g image upload)
Accept any values supported by raw-body.
The same encoding is used in the intercept method.
Ignored if parseReqBody is set to false.
app.use('/post', proxy('httpbin.org', {
reqBodyEncoding: null
}));By default, node does not express a timeout on connections. Use timeout option to impose a specific timeout. Timed-out requests will respond with 504 status code and a X-Timeout-Reason header.
app.use('/', proxy('httpbin.org', {
timeout: 2000 // in milliseconds, two seconds
}));The node-debug module is used to provide a trace debugging capability.
DEBUG=express-http-proxy npm run YOUR_PROGRAM
DEBUG=express-http-proxy npm run YOUR_PROGRAM | grep 'express-http-proxy' # to filter down to just these messagesWill trace the execution of the express-http-proxy module in order to aide debugging.
decorateRequest has been REMOVED, and will generate an error when called. See proxyReqOptDecorator and proxyReqBodyDecorator.
Resolution: Most authors will simply need to change the method name for their decorateRequest method; if author was decorating reqOpts and reqBody in the same method, this will need to be split up.
intercept has been REMOVED, and will generate an error when called. See userResDecorator.
Resolution: Most authors will simply need to change the method name from intercept to userResDecorator, and exit the method by returning the value, rather than passing it to a callback. E.g.:
Before:
app.use('/proxy', proxy('www.google.com', {
intercept: function(proxyRes, proxyResData, userReq, userRes, cb) {
data = JSON.parse(proxyResData.toString('utf8'));
data.newProperty = 'exciting data';
cb(null, JSON.stringify(data));
}
}));Now:
app.use('/proxy', proxy('www.google.com', {
userResDecorator: function(proxyRes, proxyResData, userReq, userRes) {
data = JSON.parse(proxyResData.toString('utf8'));
data.newProperty = 'exciting data';
return JSON.stringify(data);
}
}));forwardPath and forwardPathAsync have been DEPRECATED and will generate a warning when called. See proxyReqPathResolver.
Resolution: Simple update the name of either forwardPath or forwardPathAsync to proxyReqPathResolver.
When your proxy server responds with an error, express-http-proxy returns a response with the same status code. See test/catchingErrors for syntax details.
When your proxy server times out, express-http-proxy will continue to wait indefinitely for a response, unless you define a timeout as described above.
The library will automatically use https if the provided path has 'https://' or ':443'. You may also set option https to true to always use https.
You can use proxyReqOptDecorator to ammend any auth or challenge headers required to succeed https.
You can use the ability to decorate the proxy request prior to sending. See proxyReqOptDecorator for more details.
app.use('/', proxy('internalhost.example.com', {
proxyReqOptDecorator: function(proxyReqOpts, originalReq) {
proxyReqOpts.ca = [caCert, intermediaryCert]
return proxyReqOpts;
}
})You can set the rejectUnauthorized value in proxy request options prior to sending. See proxyReqOptDecorator for more details.
app.use('/', proxy('internalhost.example.com', {
proxyReqOptDecorator: function(proxyReqOpts, originalReq) {
proxyReqOpts.rejectUnauthorized = false
return proxyReqOpts;
}
}))| Release | Notes |
|---|---|
| 2.1.2 | Fixes => content-length request header is removed when parseReqBody is false (#549), implement memory leak fix (#566), fix to UserDecorator, replace httpbin in test suite, general cleanup of test and dot files |
| 2.1.1 | (trivial) Fixes formatting in README. |
| 2.1.0 | Fixes parsing error in content-types. Improves behavior of proxyReqBodyDecorator when parseReqBody=false. Repairs issue where authors can't use proxy() twice in Express middleware stack. Fix new Buffer deprecation warning. |
| 2.0.0 | Update all dependencies; set stage for next iteration. express-http-proxy interface has not changed, but the underlying libraries are not guaranteed to be backward compatible. Versions beyond this point are expected to be run in node verions >= 16. |
| ----- | ----------------------------------------------------------------------- |
| 1.6.3 | [#453] Author should be able to delete headers in userResHeaderDecorator. |
| 1.6.2 | Update node.js versions used by ci. |
| 1.6.1 | Minor bug fixes and documentation. |
| 1.6.0 | Do gzip and gunzip aysyncronously. Test and documentation improvements, dependency updates. |
| 1.5.1 | Fixes bug in stringifying debug messages. |
| 1.5.0 | Fixes bug in filter signature. Fix bug in skipToNextHandler, add expressHttpProxy value to user res when skipped. Add tests for host as ip address. |
No open issues yet, or sync has not completed.