Code Monkey home page Code Monkey logo

http-proxy-middleware's Introduction

http-proxy-middleware

GitHub Workflow Status (with branch) Coveralls Known Vulnerabilities npm

Node.js proxying made simple. Configure proxy middleware with ease for connect, express, next.js and many more.

Powered by the popular Nodejitsu http-proxy. GitHub stars

⚠️ Note

This page is showing documentation for version v3.x.x (release notes)

See MIGRATION.md for details on how to migrate from v2.x.x to v3.x.x

If you're looking for older documentation. Go to:

TL;DR

Proxy /api requests to http://www.example.org

💡 Tip: Set the option changeOrigin to true for name-based virtual hosted sites.

// javascript

const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

app.use(
  '/api',
  createProxyMiddleware({
    target: 'http://www.example.org/secret',
    changeOrigin: true,
  }),
);

app.listen(3000);

// proxy and change the base path from "/api" to "/secret"
// http://127.0.0.1:3000/api/foo/bar -> http://www.example.org/secret/foo/bar
// typescript

import * as express from 'express';
import { createProxyMiddleware, Filter, Options, RequestHandler } from 'http-proxy-middleware';

const app = express();

app.use(
  '/api',
  createProxyMiddleware({
    target: 'http://www.example.org/api',
    changeOrigin: true,
  }),
);

app.listen(3000);

// proxy and keep the same base path "/api"
// http://127.0.0.1:3000/api/foo/bar -> http://www.example.org/api/foo/bar

All http-proxy options can be used, along with some extra http-proxy-middleware options.

Table of Contents

Install

npm install --save-dev http-proxy-middleware

Basic usage

Create and configure a proxy middleware with: createProxyMiddleware(config).

const { createProxyMiddleware } = require('http-proxy-middleware');

const apiProxy = createProxyMiddleware({
  target: 'http://www.example.org',
  changeOrigin: true,
});

// 'apiProxy' is now ready to be used as middleware in a server.

Express Server Example

An example with express server.

// include dependencies
const express = require('express');
const { createProxyMiddleware } = require('http-proxy-middleware');

const app = express();

// create the proxy
/** @type {import('http-proxy-middleware/dist/types').RequestHandler<express.Request, express.Response>} */
const exampleProxy = createProxyMiddleware({
  target: 'http://www.example.org/api', // target host with the same base path
  changeOrigin: true, // needed for virtual hosted sites
});

// mount `exampleProxy` in web server
app.use('/api', exampleProxy);
app.listen(3000);

app.use(path, proxy)

If you want to use the server's app.use path parameter to match requests. Use pathFilter option to further include/exclude requests which you want to proxy.

app.use(
  createProxyMiddleware({
    target: 'http://www.example.org/api',
    changeOrigin: true,
    pathFilter: '/api/proxy-only-this-path',
  }),
);

app.use documentation:

Options

http-proxy-middleware options:

pathFilter (string, []string, glob, []glob, function)

Narrow down which requests should be proxied. The path used for filtering is the request.url pathname. In Express, this is the path relative to the mount-point of the proxy.

  • path matching

    • createProxyMiddleware({...}) - matches any path, all requests will be proxied when pathFilter is not configured.
    • createProxyMiddleware({ pathFilter: '/api', ...}) - matches paths starting with /api
  • multiple path matching

    • createProxyMiddleware({ pathFilter: ['/api', '/ajax', '/someotherpath'], ...})
  • wildcard path matching

    For fine-grained control you can use wildcard matching. Glob pattern matching is done by micromatch. Visit micromatch or glob for more globbing examples.

    • createProxyMiddleware({ pathFilter: '**', ...}) matches any path, all requests will be proxied.
    • createProxyMiddleware({ pathFilter: '**/*.html', ...}) matches any path which ends with .html
    • createProxyMiddleware({ pathFilter: '/*.html', ...}) matches paths directly under path-absolute
    • createProxyMiddleware({ pathFilter: '/api/**/*.html', ...}) matches requests ending with .html in the path of /api
    • createProxyMiddleware({ pathFilter: ['/api/**', '/ajax/**'], ...}) combine multiple patterns
    • createProxyMiddleware({ pathFilter: ['/api/**', '!**/bad.json'], ...}) exclusion

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

  • custom matching

    For full control you can provide a custom function to determine which requests should be proxied or not.

    /**
     * @return {Boolean}
     */
    const pathFilter = function (path, req) {
      return path.match('^/api') && req.method === 'GET';
    };
    
    const apiProxy = createProxyMiddleware({
      target: 'http://www.example.org',
      pathFilter: pathFilter,
    });

pathRewrite (object/function)

Rewrite target's url path. Object-keys will be used as RegExp to match paths.

// rewrite path
pathRewrite: {'^/old/api' : '/new/api'}

// remove path
pathRewrite: {'^/remove/api' : ''}

// add base path
pathRewrite: {'^/' : '/basepath/'}

// custom rewriting
pathRewrite: function (path, req) { return path.replace('/api', '/base/api') }

// custom rewriting, returning Promise
pathRewrite: async function (path, req) {
  const should_add_something = await httpRequestToDecideSomething(path);
  if (should_add_something) path += "something";
  return path;
}

router (object/function)

Re-target option.target for specific requests.

// Use `host` and/or `path` to match requests. First match will be used.
// The order of the configuration matters.
router: {
    'integration.localhost:3000' : 'http://127.0.0.1:8001',  // host only
    'staging.localhost:3000'     : 'http://127.0.0.1:8002',  // host only
    'localhost:3000/api'         : 'http://127.0.0.1:8003',  // host + path
    '/rest'                      : 'http://127.0.0.1:8004'   // path only
}

// Custom router function (string target)
router: function(req) {
    return 'http://127.0.0.1:8004';
}

// Custom router function (target object)
router: function(req) {
    return {
        protocol: 'https:', // The : is required
        host: '127.0.0.1',
        port: 8004
    };
}

// Asynchronous router function which returns promise
router: async function(req) {
    const url = await doSomeIO();
    return url;
}

plugins (Array)

const simpleRequestLogger = (proxyServer, options) => {
  proxyServer.on('proxyReq', (proxyReq, req, res) => {
    console.log(`[HPM] [${req.method}] ${req.url}`); // outputs: [HPM] GET /users
  });
},

const config = {
  target: `http://example.org`,
  changeOrigin: true,
  plugins: [simpleRequestLogger],
};

ejectPlugins (boolean) default: false

If you're not satisfied with the pre-configured plugins, you can eject them by configuring ejectPlugins: true.

NOTE: register your own error handlers to prevent server from crashing.

// eject default plugins and manually add them back

const {
  debugProxyErrorsPlugin, // subscribe to proxy errors to prevent server from crashing
  loggerPlugin, // log proxy events to a logger (ie. console)
  errorResponsePlugin, // return 5xx response on proxy error
  proxyEventsPlugin, // implements the "on:" option
} = require('http-proxy-middleware');

createProxyMiddleware({
  target: `http://example.org`,
  changeOrigin: true,
  ejectPlugins: true,
  plugins: [debugProxyErrorsPlugin, loggerPlugin, errorResponsePlugin, proxyEventsPlugin],
});

logger (Object)

Configure a logger to output information from http-proxy-middleware: ie. console, winston, pino, bunyan, log4js, etc...

Only info, warn, error are used internally for compatibility across different loggers.

If you use winston, make sure to enable interpolation: https://github.com/winstonjs/winston#string-interpolation

See also logger recipes (recipes/logger.md) for more details.

createProxyMiddleware({
  logger: console,
});

http-proxy events

Subscribe to http-proxy events with the on option:

createProxyMiddleware({
  target: 'http://www.example.org',
  on: {
    proxyReq: (proxyReq, req, res) => {
      /* handle proxyReq */
    },
    proxyRes: (proxyRes, req, res) => {
      /* handle proxyRes */
    },
    error: (err, req, res) => {
      /* handle error */
    },
  },
});
  • option.on.error: function, subscribe to http-proxy's error event for custom error handling.

    function onError(err, req, res, target) {
      res.writeHead(500, {
        'Content-Type': 'text/plain',
      });
      res.end('Something went wrong. And we are reporting a custom error message.');
    }
  • option.on.proxyRes: function, subscribe to http-proxy's proxyRes event.

    function onProxyRes(proxyRes, req, res) {
      proxyRes.headers['x-added'] = 'foobar'; // add new header to response
      delete proxyRes.headers['x-removed']; // remove header from response
    }
  • option.on.proxyReq: function, subscribe to http-proxy's proxyReq event.

    function onProxyReq(proxyReq, req, res) {
      // add custom header to request
      proxyReq.setHeader('x-added', 'foobar');
      // or log the req
    }
  • option.on.proxyReqWs: function, subscribe to http-proxy's proxyReqWs event.

    function onProxyReqWs(proxyReq, req, socket, options, head) {
      // add custom header
      proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
    }
  • option.on.open: function, subscribe to http-proxy's open event.

    function onOpen(proxySocket) {
      // listen for messages coming FROM the target here
      proxySocket.on('data', hybridParseAndLogMessage);
    }
  • option.on.close: function, subscribe to http-proxy's close event.

    function onClose(res, socket, head) {
      // view disconnected websocket connections
      console.log('Client disconnected');
    }

http-proxy options

The following options are provided by the underlying http-proxy library.

  • option.target: url string to be parsed with the url module

  • option.forward: url string to be parsed with the url module

  • option.agent: object to be passed to http(s).request (see Node's https agent and http agent objects)

  • option.ssl: object to be passed to https.createServer()

  • option.ws: true/false: if you want to proxy websockets

  • option.xfwd: true/false, adds x-forward headers

  • option.secure: true/false, if you want to verify the SSL Certs

  • option.toProxy: true/false, passes the absolute URL as the path (useful for proxying to proxies)

  • option.prependPath: true/false, Default: true - specify whether you want to prepend the target's path to the proxy path

  • option.ignorePath: true/false, Default: false - specify whether you want to ignore the proxy path of the incoming request (note: you will have to append / manually if required).

  • option.localAddress : Local interface string to bind for outgoing connections

  • option.changeOrigin: true/false, Default: false - changes the origin of the host header to the target URL

  • option.preserveHeaderKeyCase: true/false, Default: false - specify whether you want to keep letter case of response header key

  • option.auth : Basic authentication i.e. 'user:password' to compute an Authorization header.

  • option.hostRewrite: rewrites the location hostname on (301/302/307/308) redirects.

  • option.autoRewrite: rewrites the location host/port on (301/302/307/308) redirects based on requested host/port. Default: false.

  • option.protocolRewrite: rewrites the location protocol on (301/302/307/308) redirects to 'http' or 'https'. Default: null.

  • option.cookieDomainRewrite: rewrites domain of set-cookie headers. Possible values:

    • false (default): disable cookie rewriting

    • String: new domain, for example cookieDomainRewrite: "new.domain". To remove the domain, use cookieDomainRewrite: "".

    • Object: mapping of domains to new domains, use "*" to match all domains.
      For example keep one domain unchanged, rewrite one domain and remove other domains:

      cookieDomainRewrite: {
        "unchanged.domain": "unchanged.domain",
        "old.domain": "new.domain",
        "*": ""
      }
  • option.cookiePathRewrite: rewrites path of set-cookie headers. Possible values:

    • false (default): disable cookie rewriting

    • String: new path, for example cookiePathRewrite: "/newPath/". To remove the path, use cookiePathRewrite: "". To set path to root use cookiePathRewrite: "/".

    • Object: mapping of paths to new paths, use "*" to match all paths. For example, to keep one path unchanged, rewrite one path and remove other paths:

      cookiePathRewrite: {
        "/unchanged.path/": "/unchanged.path/",
        "/old.path/": "/new.path/",
        "*": ""
      }
  • option.headers: object, adds request headers. (Example: {host:'www.example.org'})

  • option.proxyTimeout: timeout (in millis) when proxy receives no response from target

  • option.timeout: timeout (in millis) for incoming requests

  • option.followRedirects: true/false, Default: false - specify whether you want to follow redirects

  • option.selfHandleResponse true/false, if set to true, none of the webOutgoing passes are called and it's your responsibility to appropriately return the response by listening and acting on the proxyRes event

  • option.buffer: stream of data to send as the request body. Maybe you have some middleware that consumes the request stream before proxying it on e.g. If you read the body of a request into a field called 'req.rawbody' you could restream this field in the buffer option:

    'use strict';
    
    const streamify = require('stream-array');
    const HttpProxy = require('http-proxy');
    const proxy = new HttpProxy();
    
    module.exports = (req, res, next) => {
      proxy.web(
        req,
        res,
        {
          target: 'http://127.0.0.1:4003/',
          buffer: streamify(req.rawBody),
        },
        next,
      );
    };

WebSocket

// verbose api
createProxyMiddleware({ pathFilter: '/', target: 'http://echo.websocket.org', ws: true });

External WebSocket upgrade

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.

const wsProxy = createProxyMiddleware({ target: 'ws://echo.websocket.org', changeOrigin: true });

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

const server = app.listen(3000);
server.on('upgrade', wsProxy.upgrade); // <-- subscribe to http 'upgrade'

Intercept and manipulate requests

Intercept requests from downstream by defining onProxyReq in createProxyMiddleware.

Currently the only pre-provided request interceptor is fixRequestBody, which is used to fix proxied POST requests when bodyParser is applied before this middleware.

Example:

const { createProxyMiddleware, fixRequestBody } = require('http-proxy-middleware');

const proxy = createProxyMiddleware({
  /**
   * Fix bodyParser
   **/
  on: {
    proxyReq: fixRequestBody,
  },
});

Intercept and manipulate responses

Intercept responses from upstream with responseInterceptor. (Make sure to set selfHandleResponse: true)

Responses which are compressed with brotli, gzip and deflate will be decompressed automatically. The response will be returned as buffer (docs) which you can manipulate.

With buffer, response manipulation is not limited to text responses (html/css/js, etc...); image manipulation will be possible too. (example)

NOTE: responseInterceptor disables streaming of target's response.

Example:

const { createProxyMiddleware, responseInterceptor } = require('http-proxy-middleware');

const proxy = createProxyMiddleware({
  /**
   * IMPORTANT: avoid res.end being called automatically
   **/
  selfHandleResponse: true, // res.end() will be called internally by responseInterceptor()

  /**
   * Intercept response and replace 'Hello' with 'Goodbye'
   **/
  on: {
    proxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
      const response = responseBuffer.toString('utf8'); // convert buffer to string
      return response.replace('Hello', 'Goodbye'); // manipulate response and return the result
    }),
  },
});

Check out interception recipes for more examples.

Node.js 17+: ECONNREFUSED issue with IPv6 and localhost (#705)

Node.js 17+ no longer prefers IPv4 over IPv6 for DNS lookups. E.g. It's not guaranteed that localhost will be resolved to 127.0.0.1 – it might just as well be ::1 (or some other IP address).

If your target server only accepts IPv4 connections, trying to proxy to localhost will fail if resolved to ::1 (IPv6).

Ways to solve it:

  • Change target: "http://localhost" to target: "http://127.0.0.1" (IPv4).
  • Change the target server to (also) accept IPv6 connections.
  • Add this flag when running node: node index.js --dns-result-order=ipv4first. (Not recommended.)

Note: There’s a thing called Happy Eyeballs which means connecting to both IPv4 and IPv6 in parallel, which Node.js doesn’t have, but explains why for example curl can connect.

Debugging

Configure the DEBUG environment variable enable debug logging.

See debug project for more options.

DEBUG=http-proxy-middleware* node server.js

$ http-proxy-middleware proxy created +0ms
$ http-proxy-middleware proxying request to target: 'http://www.example.org' +359ms

Working examples

View and play around with working examples.

Recipes

View the recipes for common use cases.

Compatible servers

http-proxy-middleware is compatible with the following servers:

Sample implementations can be found in the server recipes.

Tests

Run the test suite:

# install dependencies
$ yarn

# linting
$ yarn lint
$ yarn lint:fix

# building (compile typescript to js)
$ yarn build

# unit tests
$ yarn test

# code coverage
$ yarn cover

# check spelling mistakes
$ yarn spellcheck

Changelog

License

The MIT License (MIT)

Copyright (c) 2015-2022 Steven Chim

http-proxy-middleware's People

Contributors

all-less avatar aremishevsky avatar bangank36 avatar bforbis avatar chimurai avatar cloudmu avatar crooruhe avatar davidmeirlevy avatar dependabot[bot] avatar dflock avatar dylang avatar flackenstein avatar graingert avatar kevinxh avatar klimashkin avatar leonardobazico avatar liranbri avatar lpaolini avatar maapteh avatar maple3142 avatar mcgwiz avatar mhassan1 avatar michaeltazelaar avatar midgleyc avatar oufeng avatar rsethc avatar sorin-davidoi avatar stefanwright1988 avatar tigge avatar trysound avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

http-proxy-middleware's Issues

POST request body is not proxied to the servers

I have in my backend defined:

var proxy = proxyMiddleware('/api', {
        target: 'http://somehost.zero',
        proxyTable: {
            '/api/one': 'http://somehost.one',
            '/api/two': 'http://somehost.two',
        }
    });
app.use(proxy);

and when I'm proxing POST request (lets say to the '/api/one': 'http://somehost.one' ) I don't know why but server http://somehost.one get request without body.

Did you had similar problem?

Proxy error: ECONNREFUSED (Laravel)

Im trying to foward all requests from my Express app that runs on port 4365 to another application that runs on port 9000.
In my case im trying to build a Laravel app that will be used only for api porpuses and angular app that will use that api.

This is the code i use:

var app             = require('express')()
    , proxyMiddleware = require('http-proxy-middleware')
    , http          = require('http').Server(app);
var context = '/api'; 
var options = {
    target: 'http://localhost:9000', // target host
    changeOrigin: true,               // needed for virtual hosted sites
    ws: true,                         // proxy websockets
};
app.use(proxyMiddleware(context, options));
http.listen(4365, "localhost", function(){
    console.log('Express server is listening on Port 4365 ');
});

Assume i have Laravel app running on port 9000 with api routing valid.
When i run it and open the browser and type in the url: http:\localhost:4365\api\v1\comments i assume to get the json, but it shows me an error: "Error occured while trying to proxy to: localhost:4365/api/v1/comments"

console output:
[HPM] Proxy created: /api -> http://localhost:9000
Express server is listening on Port 4365
[HPM] Proxy error: ECONNREFUSED. localhost -> "localhost:9000/api/v1/comments"

x-www-form-urlencoded

Hi.
Header 'Content-Type: application/x-www-form-urlencoded'
Not working...
Error:
[HPM] Proxy error: ECONNRESET. localhost -> "api.*.com/oauth/token"

Client certificate isn't been recognized

Hi,

I'm creating a proxy to a server that uses certificate authentication.

    server.middleware = proxyMiddleware('/providers/sse/services/scim',
        {target: 'https://backendserver.com',
          changeOrigin: true,
          port: 443,
          secure: true,  // ignore cert errors
          agent: false,
          https: {
            key: fs.readFileSync('private_key.pem'),
            cert: fs.readFileSync('client_cert.pem')
          },
        });

However, when I connect to my server, I'm being prompted for the credentials when the request is being forwarded to the backend server.

At the same time, the following code (written by someone else) that creates an http server directly, passing the same client certificate data, passes the client cert data successfully, and I can retrieve data from the backend server without a prompt:

http.createServer(onRequest).listen(3030);

function onRequest(client_req, client_res) {

  var options = {
    key: fs.readFileSync('private_key.pem'),
    cert: fs.readFileSync('client_cert.pem'),
    agent: false,
    host: backendserver,
    method: client_req.method,
    path: client_req.url,
    headers:{
        Host: backendserver
    }
  };

  var proxy = https.get(options, function(res) {
    client_res.on('data', function(d) {
  });

  res.pipe(client_res, {
      end: true
    });
  });

  client_req.pipe(proxy, {
    end: true
  });

Any idea of what might be wrong?

[HPM] Proxy error: ECONNREFUSED

Hi, I am serving a web application with gulp.js in port 3000, and a php backend application served in port 8000.

I am trying to use http-proxy-middleware in my gulp serve task in order to defer any calls from localhost:3000/api to my api endpoint at: localhost:8000/api. I have used it as follows:

proxyMiddleware('/api', { target: 'http://localhost:8000' });

For instance if I try to POST to api/authenticate, nodejs gives me in the console:
[HPM] Proxy error: ECONNREFUSED localhost:8000/api/authenticate

So what I can see here is that it's actually trying to proxy it, but returns this unexpected error. Inspecting the network response I get:

Error occured while trying to proxy to: localhost:3000/api/authenticate

I don't know if this problem is related to myself using this module in an incorrect manner, any help would be very appreciated. Thanks in advance.

Proxy Failure on WS Proxy Server Connection Close

HTPM just got merged into webpack(webpack/webpack-dev-server#359) which is awesome because it enables things like native websockets which didn't work previously.

I was just taking it for a spin and everything was working great until I took down the backend server before shutting down the dev-server. The logic in my front-end is such that after the socket dies it will recheck if it is logged in (hence the /api/users/me check). I can work on an example but it may take me a little while, wondering if it might be obvious from these logs + stack trace:

[HPM] Upgrading to WebSocket
[HPM] Client disconnected
[HPM] Proxy error: ECONNREFUSED. 127.0.0.1 -> "127.0.0.1:9020/api/users/me"
[HPM] Upgrading to WebSocket
./node_modules/webpack-dev-server/node_modules/http-proxy-middleware/lib/handlers.js:8
        res.writeHead(500);
            ^

TypeError: res.writeHead is not a function
    at ProxyServer.proxyError (./node_modules/webpack-dev-server/node_modules/http-proxy-middleware/lib/handlers.js:8:13)
    at ProxyServer.emit (./node_modules/webpack-dev-server/node_modules/http-proxy-middleware/node_modules/http-proxy/node_modules/eventemitter3/index.js:117:27)
    at ClientRequest.onOutgoingError (./node_modules/webpack-dev-server/node_modules/http-proxy-middleware/node_modules/http-proxy/lib/http-proxy/passes/ws-incoming.js:153:16)
    at emitOne (events.js:77:13)
    at ClientRequest.emit (events.js:169:7)
    at Socket.socketErrorListener (_http_client.js:259:9)
    at emitOne (events.js:77:13)
    at Socket.emit (events.js:169:7)
    at emitErrorNT (net.js:1257:8)
    at doNTCallback2 (node.js:441:9)
    at process._tickCallback (node.js:355:17)

Im totally expecting the proxy to fail and even loudly complain, but I wouldn't expect it to crash the dev-server. If there's some hardening that must be done on the webpack-dev-server itself instead we can get a PR there.

Log levels

Introduce option.logLevel:

  • debug
  • info
  • warn
  • error
  • silent

Ability to control the log levels or disable logging.

Proxy websocket when using gulp, browsersync, ng-websocket

Hi,

Can you please review the http-proxy-middleware config below?

I'm not able to proxy local websocket (separate) process with http-proxy-middleware as I see "[HPM] Upgrading to WebSocket" message on the window where I ran "gulp serve", and the error "WebSocket connection to 'ws://localhost:3000/ws/myobjects' failed: Connection closed before receiving a handshake response" on the browser console window.

I'm using v0.9.0 of http-proxy-middleware, v0.2.1 of ng-websocket, v2.8.3 of browser-sync.

When browser makes a websocket call to "ws://localhost:3000/ws/myobjects" I expect the call to be served by a server listening for web socket connection on "ws://localhost:10009/ws/myobjects"
There are other static assets served under http://localhost:3000 that are not related to websockets.

function browserSyncInit(baseDir, browser) {
  browser = browser === undefined ? 'default' : browser;

  var routes = null;
  if(baseDir === conf.paths.src || (util.isArray(baseDir) && baseDir.indexOf(conf.paths.src) !== -1)) {
    routes = {
      '/bower_components': 'bower_components'
    };
  }

  var server = {
    baseDir: baseDir,
    routes: routes
  };

  /*
   * You can add a proxy to your backend by uncommenting the line bellow.
   * You just have to configure a context which will we redirected and the target url.
   * Example: $http.get('/users') requests will be automatically proxified.
   *
   * For more details and option, https://github.com/chimurai/http-proxy-middleware/blob/v0.0.5/README.md
   */
   server.middleware = proxyMiddleware('/ws/myobjects', {
     target: 'http://localhost:10009',
     ws: true,
     changeOrigin : true,
     proxyTable: {
       'localhost:3000/ws/myobjects' : 'http://localhost:10009'
     }
   });

  browserSync.instance = browserSync.init({
    startPath: '/',
    server: server,
    browser: browser
  });
}

wildcard / glob support

Extend the current "context" matching, in order to have more control on which requests to proxy or not to proxy.

Running subapps and applying proxy

Hi,

First of all thanks for the module, i tried it out and works fine. I'm looking for suggestions for my current use-case

I have 3 apps, a, b and c, where a is main app

a - main app running in port 80

  • route.js
    • app.get('/a',function(){})

b - sub app running in port 8001

  • route.js
    • app.get('/',function(){})

c - sub app running in port 8002

  • route.js
    • app.get('/',function(){})

In app a code look like this

   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.');
    }

    var serverB = 'http://localhost:8001';
    var serverC = 'http://localhost:8002';

    var proxyB = proxyMiddleware('/b', {target: serverB, onError : onError});
    var proxyC = proxyMiddleware('/c', {target: serverC, onError : onError});
    app.use(proxyB );
    app.use(proxyC );

I will bring down b or c for deployment and will be showing maintenance page accordingly.

Like to know if this configuration is good enough to support my usecase.
Please share your thoughts

Websocket in Gulp(Ionic)

I copy your code in gulpfile.js

var proxy = require('http-proxy-middleware');

gulp.task('connect', function() {
     connect.server({
       root: ['./app'],
       port: 2301,
       middleware: function(connect, opt) {
         return [
           proxy('/socket', {
             target: 'https://cloud.vanwardsmart.com',
             changeOrigin:true,
             ws: true,      // <-- set it to 'true' to proxy WebSockets
             secure:true
           })
         ]
       }
     });
 });

gulp.task('default', ['connect']);

when I use create websocket instance, just like this:

  var wsUrl = 'wss://192.1.10.80:2301/ws';
  var ws = new WebSocket(wsUrl);

the browser show "failed: Error in connection establishment: net::ERR_CONNECTION_REFUSED" error

Impossible to ignore proxy path prefix

Hi,

I need to proxy requests from /api to the root of other site: http://test.com:

/api/users -> http://test.com/users
/api/users/1 -> http://test.com/users/1

But all my requests lead to http://test.com/api/*
How to ignore /api prefix but not to ignore other path?
When I use ignorePath settings all my requests lead to http://test.com.

Config:

server.middleware = proxyMiddleware('/api', {target: 'http://test.com', proxyHost: 'test.com'});

Handling relative paths

Hi,

I am trying to use the proxy in the following setup :

//Hosted on http://localhost:4000
var proxyMiddleware = require('http-proxy-middleware');
var proxy = proxyMiddleware('/api/materials/Csi/Model', {
  target: 'http://localhost:8080/newApp',
  changeOrigin: true
});
app.use(proxy);

Now when I do - http://localhost:4000/api/materials/Csi/Model it does load the target but the dependencies pop out a 404 error.

I fixed for now using apache2 using mod_proxy (proxy reverse), but I want to use your npm module as can add route based authentication when on port 4000.

Thanks
Gautam

Allow to subscribe to websocket http upgrade externally

Listen to upgrade event externally, without hitchhiking on a initial http request.

var app = express();
var proxy = proxyMiddleware('http://www.example.org/api', {ws:true, changeOrigin: true});

app.use(proxy);

var server = app.listen(3000);

server.on('upgrade', proxy.upgrade);  // <-- directly subscribe to server's upgrade event.

Use proxy response cookie for further proxy request

Expected behavior

Not able to save cookies from proxy response to the session.

Actual behavior

Setup

  • http-proxy-middleware: 0.15.0
  • server: express + 4.13.3

proxy middleware configuration

const proxyOptions = {
  target: targetUrl,                // target host
  pathRewrite: function (path) {
    return path.replace('/api', '')
  },
  logLevel: 'debug',
  onProxyReq: function (proxyReq, req, rsp) {
    proxyReq.path = req.path + '?ticket=' + req.session.pt[targetUrl]
    if(req.session.cookie.pt_session_id && req.session.cookie.pt_session_id[targetUrl]) {
      proxyReq.writeHead(req.session.cookie.pt_session_id[targetUrl])
    }
  },
  onProxyRes: function onProxyRes(proxyRes, req, res) {
    console.log('RAW Response from the target', JSON.stringify(proxyRes.headers, true, 2))
    req.session.cookie.pt_session_id = req.session.cookie.pt_session_id || {}
    req.session.cookie.pt_session_id[targetUrl] = proxyRes.headers['set-cookie']
  }
}
var apiProxy = proxy('/api', proxyOptions);

server mounting

var app = express();

app.use(apiProxy);
app.listen(3000);

Hi,

Thanks guys for the awesome middleware which made my life very easy. We need minor information regarding my usecase. We are implementing CAS proxy using then middleware. Our cas server behaviour is it, first time it accept the proxy ticket and provides the _session_id, it expects that _session_id in further request. I am not able to save it to session and use it. Have I missed something. ?

proxy response looks like below:

RAW Response from the target {
   "server": "nginx/1.6.2",
   "date": "Fri, 13 May 2016 06:38:26 GMT",
   "content-type": "application/json;charset=utf-8",
   "content-length": "2071",
   "connection": "close",
   "status": "200 OK",
   "set-cookie": [
     "_session_id=randombignumber; path=/; HttpOnly"
   ]
}

expose http-proxy proxyRes event

ability to subscribe to http-proxy proxyRes event to inspect and modify the response.
example:

  • add/remove/modify response headers.

websocket problems (browser-sync + http-proxy-middleware)

so, I'm trying to proxy a websocket within gulp, using http-proxy-middleware.

my backend server code is this

var app = require('express')();
var server = require('http').createServer(app);
var io = require('socket.io')(server,{ path: '/socket.io'});
io.on('connection', function(){ console.log("woot! connection")/* … */ });
server.listen(5000);

and my gulp code is this

  var server = {
    baseDir: baseDir,
    routes: routes
  };

  var proxies = [];

  proxies.push(proxyMiddleware('/socket.io', { target: 'http://localhost:5000/' , ws: true}));
  server.middleware = proxies;

  browserSync.instance = browserSync.init({
    startPath: '/',
    server: server,
    browser: browser
  });

on the console I see

woot! connection
[HPM] Upgrading to WebSocket
[HPM] Client disconnected

and the client console has

WebSocket connection to 'ws://mysite.io/socket.io/?EIO=3&transport=websocket&sid=5_BeDfck0LFYcYxPAAAA' failed: Error during WebSocket handshake: Unexpected response code: 502

Am I missing something ?

thanks

custom proxy error handler

add ability to override the default http-proxy error handling:

  • to return a different http status code.
  • to return a different response.
  • to return nothing.
  • etc...

Api behind Basic authentication and NTLM authentication

Hi, I have api on iis server behind basic windows authentication and i cannot use cors. So I tried to use this module but however I configure it I cannot log into api and I get 401 every time

I tried

    server.middleware = proxyMiddleware(
        '/api',
        {
            target: 'API_HOST',
            logLevel: 'debug'
        }
    );
    server.middleware = proxyMiddleware(
        '/api',
        {
            target: 'API_HOST',
            logLevel: 'debug',
            auth: 'LOGIN:PASS'
        }
    );
    server.middleware = proxyMiddleware(
        '/api',
        {
            target: 'http://LOGIN:PASS@API_HOST',
            logLevel: 'debug'
        }
    );

Disable SSL cert checking

Hi is this possible ? I'm running against a dev server and can't get a valid cert until we go to prod.

How to log request and response urls?

I would like to log each request no matter what status code the target server responded. I'm trying to achieve the following format:

// Format:
// -->  [METHOD] [PATH_REQUESTED_FROM_PROXY] -> [URL_REQUESTED_FROM_TARGET]
// Example:
// -->  GET /v1/users/123 -> https://my-app.herokuapp.com/api/v1/users/123

My proxy options are:

var proxyOpts = {
    target: 'https://my-app.herokuapp.com/',
    pathRewrite: {
        '^/v1' : '/api/v1'
    },
    onProxyReq: function onProxyReq(proxyReq, req, res) {
        // Log outbound request to remote target
        console.log('-->  ', req.method, req.path, '->', proxyReq.baseUrl + proxyReq.path);
    },
    onError: function onError(err, req, res) {
        console.error(err);
        res.status(500);
        res.json({error: 'Error when connecting to remote server.'});
    },
    logLevel: 'debug',
    changeOrigin: true,
    secure: true
};

Which outputs:

-->   GET /api/v1/users/123 -> undefined/api/v1/users/123

Problems:

  • req.path is already converted to the new format with pathRewrite, I would want to log the url which client actually requested from this proxy server
  • proxyReq.baseUrl is not defined, I'm not sure what I should use to get the host part of the request.

add proxyTable support

Suggested in #4 (comment)

proxyTable option allows you to use a different option.target based on host request header and optional path.

Proposal:

proxyMiddleware('/api', {
  target: 'http://www.example.org',
  proxyTable : {
    'foo.com/api': 'http://website.com:8000',
    'foo.com': 'http://website.com:8001',
    'bar.com': 'http://website2.com:8002'
  }
});

How can I proxy only GET method

I would like to proxy only some type of methods (in case I have REST api on same url with GET and POST method). Server has implemented only POST method and I should test only that. I can't specify just to proxy POST.

Is it possible to add that feature?

feature: add `router` option to dynamically route to different `target`

Allow user to provide a function to (re)route to a different target; context information from the request object can be used to determine the target as user wishes.

var apiProxy = proxy('/api', {
  target: 'http://localhost:1234',
  router: function (req) {
    return 'http://newtarget.localhost:5000';
    // return;  // to use default `target`
  }
});

Deprecate proxyTable in favor of router. The proxyTable functionality can still be used by providing a map (proxyTable) with routing rules.

var proxyTable = {
    "integration.localhost:3000" : "http://localhost:8001",    // host only
    "staging.localhost:3000"     : "http://localhost:8002",    // host only
    "localhost:3000/api"         : "http://localhost:8003",    // host + path
    "/rest"                      : "http://localhost:8004"     // path only
};

var apiProxy = proxy('/api', {
  target: 'http://localhost:1234',
  router: proxyTable
});

References:

Support shorthand proxy configuration

Support shorthand proxy configuration.

Set target = http://www.example.org and proxy everything:

var proxy = proxyMiddleware('http://www.example.org');
// equals:  proxyMiddleware('/', {target: 'http://www.example.org'});

Set target = http://www.example.org and context = '/api':

var proxy = proxyMiddleware('http://www.example.org/api');
// equals:  proxyMiddleware('/api', {target: 'http://www.example.org'});

Change target at runtime

Hi! It would be great to have some method to change proxy target in runtime by some user interaction!
Without restarting express or httpserver

Expose `proxyReqWs` events

We can add a onProxyReqWs callback analogous to onProxyReq for the proxyReq events.

Alternatively, we could expose the proxy object itself. That'd probably give the user the most flexibility in attaching callbacks.

Edit proxy request/response POST parameters

Hello Chimurai,

I was hoping you might have some suggestions on how to edit the POST parameters prior to submitting the request to the target and redacting/removing sensitive parameters in the response prior to forwarding to the client? I can find a number of options to trap the body content using modules like getRawBody or using the req.on('data',..) to capture the form parameters but I can't find anything that would allow for the manipulation of the rawBody for both the request or response.

Hoping you might be able to shed some light on this problem?

Respectfully,

Warren.

sockjs: WebSocketSession not yet initialized

I am having problems proxying SockJS websockets. On the server side I am getting "WebSocketSession not yet initialized". On the client side I am getting "failed: Invalid frame header". It looks like it almost connects, but something goes wrong in handshake. Any ideas?

Here's my proxy configuration.

var gulp            = require('gulp');
var express         = require('express');
var proxyMiddleware = require('http-proxy-middleware');

gulp.task('serve', function() {
    proxy = proxyMiddleware('/go', {
        target: 'http://localhost:8080/',
        ws: true,
    });

    var app = express();
    app.use('/', express.static('./build/'));             
    app.use(proxy);                                       

    var server = app.listen(3000);
    server.on('upgrade', proxy.upgrade);                  
});

gulp.task('build', function(){
    gulp.src('src/**/*.*')
        .pipe(gulp.dest('./build/go/'));
});

Network tab:
General

Request URL:ws://localhost:3000/go/xxxxxxxxxx/websocket
Request Method:GET
Status Code:101 Switching Protocols

Response Headers

view source
connection:upgrade
date:Sun, 20 Mar 2016 20:59:11 GMT
sec-websocket-accept:sPIVWZeoUMNdIxL4EHnYgvBoZng=
sec-websocket-extensions:permessage-deflate;client_max_window_bits=15
server:Apache-Coyote/1.1
upgrade:websocket

EventSource not working

I don't know if this is a http-proxy-middleware problem or a browser-sync problem (reported there as well BrowserSync/browser-sync#872) but I can't get EventSource to work when using this combination.

I am trying to use EventSource from my node-js app and push events to the client -

Has anyone managed to get this working ? I have no errors, no messages on the console but also no events. :(

If I run an example app just using node, things work fine so I know it's a problem with the combination of browser-sync and http-proxy-middleware

thanks

proxy to https errors in Node 0.12

Hi,

When proxying to https, ie:

var myProxy = httpProxyMiddleware('/my-path', {target: 'https://mysslexample.com'});

I first get a 'Proxy created' message, but then when I try to go to /my-path, I get the following error:

[HPM] Proxy error: undefined mysslexample.com/my-path

and nothing works. It works in Node 0.10.33, but not in Node 0.12. Is this an http-proxy-middleware issue or an http-proxy issue?

Thanks!

TypeError: Cannot read property 'originalUrl' of undefined

Expected behavior

No Error

Actual behavior

Error

HPM] Proxy created: /  ->  http://localhost/
[HPM] Subscribed to http-proxy events:  [ 'error', 'close' ]
/ .. ...  .. ..... /node_modules/http-proxy-middleware/index.js:38
        req.url = req.originalUrl;
                     ^
TypeError: Cannot read property 'originalUrl' of undefined
    at middleware (/media/stefano/Windows8_OS/Tinvention/tinvention/tinvention/consulenze/Unicredit/ExCeed/configDB/30_sviluppo/config_db_client/trunk/node_modules/http-proxy-middleware/index.js:38:22)

Setup

  • http-proxy-middleware: version -> "http-proxy-middleware": "0.15.0",
  • server: connect/express/browser-sync... + version -> "browser-sync": "^2.10.0",

proxy middleware configuration

var proxyMiddleware = require("http-proxy-middleware");


var proxyTable = {
    "/exx" : "http://localhost:5000/exx",    // host only
    "/configclient"     : "http://localhost:3000"    // host only
};

var options = {
    target: 'http://localhost/',
    proxyTable: proxyTable,
    logLevel: 'debug',
    changeOrigin: false
};

var proxyMidd = proxyMiddleware(options);

server mounting

browser-sync start -c ./bs-config.js

bs-config.js:

module.exports = {
    "ui": {
        "port": 3001,
        "weinre": {
            "port": 8080
        }
    },
    "files": false,
    "watchOptions": {},
    //"server": false,
    "server": {
        baseDir: "./"
    } ,
    "proxy": [ proxyMidd() ],
    "port": 3000,
    "middleware": [ historyApiFallback() ],
   ...

Add support for redirection to corporate proxy

Hello,

I'm working behind a corporate proxy, and I can't seem to make redirection work through it.

Here is my config:

{
  context: '/api',
  options: {
    pathRewrite: { '^/api' : '' },
    target: 'http://api.stuff.com',
    changeOrigin: true,
    toProxy: 'http://x.x.x.x:8080/'
  }

Maybe it's a misuse of the toProxy option, but I can't find a good example usage.

In another hand, it would be nice to make use of the standard http_proxy and https_proxy environment variables to make this work automatically without having to fiddle through the config (most node modules use these to work through corporate proxies).

Thanks for your help

Custom log provider

Introduce option.logProvider

Ability to use a custom log provider, such as:

  • winston
  • log4js

Default logProvider uses console to do the logging.

option.logProvider = function (provider) {

   // override logger.error()
   provider.error = function (message) {
      // do something
   }

   return provider
}

Or complete replace the default log provider:

option.logProvider = function () {

   var provider = {
      log : console.log,
      debug : console.log,    // use .log(); console does not have .debug()
      info : console.info,
      warn : console.warn,
      error : console.error
   };

   return provider
}

pathRewriter happening before ProxyTable

Hi,

My config are like the following one:

(pathRewrite)
{ '^/api/one' : '', '^/api/two' : '' }

and

(proxyTable)
{ '/one' : 'http://localhost:3001', '/two' : 'http://localhost:3002' }

My use case is that I need the complete path to choose the correct proxy, and only after that it should apply my rules concerning pathRewrite.

If I put the pathRewrite step after the proxyTable one, it works well.

Have I missed something?
What would be a solution?

Proxy target supports local file path

I write some local mockup files to debug APIs when server-side is not ready.
It will be nice to write file path in target to proxy local file.

proxyMiddleware('/login/verify', {
    target: 'file:///home/someone/mockup',
    pathRewrite: {
      '^/login/verify': 'login-verify.json'
    }
})

How to configure tunneling proxy

Problem Description

I am using proxy middleware to communicate with an endpoint which lives in open internet but I am behind a corporate proxy. So when I try to connect to the endpoint I am getting following error.

ROXY ERROR: ENOTFOUND. localhost:3000 -> https://www.example.com.au/login

I wonder how to configure agent for http-proxy-middleware.

I have tested a simple https with a agent and works fine and code as follows.

var tunnel = require('tunnel');
var tunnelingAgent = tunnel.httpsOverHttp({
  proxy: {
    host: 'office.proxy.com.au',
    port: 8080
  }
})

var https = require('https')
  var post_req = https.request({
    host: 'www.example.com.au',
    port: '443',
    path: '/logon',
    method: 'GET',
    agent: tunnelingAgent,
    timeout: 10000,
    followRedirect: true,
    maxRedirects: 10
  }, function(res) {
    res.setEncoding('utf8');
    res.on('data', function (chunk) {
      console.log('Response: ' + chunk);
    });
  });
  post_req.write("name=mario");
  post_req.end();

Correctly proxy connect/express when proxy is mounted with the optional path

Support different ways of mounting:

app.use(proxy('/api', {target:'http://www.example.org'}));
app.use(proxy('http://www.example.org/api'));    // <-- shorthand 
app.use('/api', proxy('http://www.example.org'));   // <-- with optional path + shorthand

http://expressjs.com/4x/api.html#app.use
When optional path is configured, requests to /api/books/123 should be proxied to http://www.example.org/api/books/123

var proxy = require('http-proxy-middleware');

app.use('/api', proxy('http://www.example.org'));

lost session with multiples hosts

I use multiple host on a proxy configuration. When I call several at the same time , I 'm losing session and the rest call always returns error 204 No content.

Any idea?

Confusing docs around path rewrite

The documentation around the path rewrite config object is a bit confusing. One could infer that the object matches as many times it can against the path when in reality it stops as soon as it hits the first match.

https://github.com/chimurai/http-proxy-middleware/blob/master/lib/path-rewriter.js#L28

I am also not sure if _.forEach is the best choice here either as it further drives home the idea of cycling through everything.

Plus it seems like there could be use cases for looping through a set of simple rewrites against one path instead of overly complex keys to match in one go.

There is also no mention of priority, and how can priority even be guaranteed since you are using _.forIn on object keys.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.