|
|
var _ = require('lodash') var httpProxy = require('http-proxy') var configFactory = require('./config-factory') var handlers = require('./handlers') var contextMatcher = require('./context-matcher') var PathRewriter = require('./path-rewriter') var Router = require('./router') var logger = require('./logger').getInstance() var getArrow = require('./logger').getArrow
module.exports = HttpProxyMiddleware
function HttpProxyMiddleware(context, opts) { // https://github.com/chimurai/http-proxy-middleware/issues/57
var wsUpgradeDebounced = _.debounce(handleUpgrade) var wsInitialized = false var config = configFactory.createConfig(context, opts) var proxyOptions = config.options
// create proxy
var proxy = httpProxy.createProxyServer({}) logger.info( '[HPM] Proxy created:', config.context, ' -> ', proxyOptions.target )
var pathRewriter = PathRewriter.create(proxyOptions.pathRewrite) // returns undefined when "pathRewrite" is not provided
// attach handler to http-proxy events
handlers.init(proxy, proxyOptions)
// log errors for debug purpose
proxy.on('error', logError)
// https://github.com/chimurai/http-proxy-middleware/issues/19
// expose function to upgrade externally
middleware.upgrade = wsUpgradeDebounced
return middleware
function middleware(req, res, next) { if (shouldProxy(config.context, req)) { var activeProxyOptions = prepareProxyRequest(req) proxy.web(req, res, activeProxyOptions) } else { next() }
if (proxyOptions.ws === true) { // use initial request to access the server object to subscribe to http upgrade event
catchUpgradeRequest(req.connection.server) } }
function catchUpgradeRequest(server) { // subscribe once; don't subscribe on every request...
// https://github.com/chimurai/http-proxy-middleware/issues/113
if (!wsInitialized) { server.on('upgrade', wsUpgradeDebounced) wsInitialized = true } }
function handleUpgrade(req, socket, head) { // set to initialized when used externally
wsInitialized = true
if (shouldProxy(config.context, req)) { var activeProxyOptions = prepareProxyRequest(req) proxy.ws(req, socket, head, activeProxyOptions) logger.info('[HPM] Upgrading to WebSocket') } }
/** * Determine whether request should be proxied. * * @private * @param {String} context [description] * @param {Object} req [description] * @return {Boolean} */ function shouldProxy(context, req) { var path = req.originalUrl || req.url return contextMatcher.match(context, path, req) }
/** * Apply option.router and option.pathRewrite * Order matters: * Router uses original path for routing; * NOT the modified path, after it has been rewritten by pathRewrite * @param {Object} req * @return {Object} proxy options */ function prepareProxyRequest(req) { // https://github.com/chimurai/http-proxy-middleware/issues/17
// https://github.com/chimurai/http-proxy-middleware/issues/94
req.url = req.originalUrl || req.url
// store uri before it gets rewritten for logging
var originalPath = req.url var newProxyOptions = _.assign({}, proxyOptions)
// Apply in order:
// 1. option.router
// 2. option.pathRewrite
__applyRouter(req, newProxyOptions) __applyPathRewrite(req, pathRewriter)
// debug logging for both http(s) and websockets
if (proxyOptions.logLevel === 'debug') { var arrow = getArrow( originalPath, req.url, proxyOptions.target, newProxyOptions.target ) logger.debug( '[HPM] %s %s %s %s', req.method, originalPath, arrow, newProxyOptions.target ) }
return newProxyOptions }
// Modify option.target when router present.
function __applyRouter(req, options) { var newTarget
if (options.router) { newTarget = Router.getTarget(req, options)
if (newTarget) { logger.debug( '[HPM] Router new target: %s -> "%s"', options.target, newTarget ) options.target = newTarget } } }
// rewrite path
function __applyPathRewrite(req, pathRewriter) { if (pathRewriter) { var path = pathRewriter(req.url, req)
if (typeof path === 'string') { req.url = path } else { logger.info('[HPM] pathRewrite: No rewritten path found. (%s)', req.url) } } }
function logError(err, req, res) { var hostname = (req.headers && req.headers.host) || (req.hostname || req.host) // (websocket) || (node0.10 || node 4/5)
var target = proxyOptions.target.host || proxyOptions.target var errorMessage = '[HPM] Error occurred while trying to proxy request %s from %s to %s (%s) (%s)' var errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors' // link to Node Common Systems Errors page
logger.error( errorMessage, req.url, hostname, target, err.code || err, errReference ) } }
|