diff --git a/README.md b/README.md index d5a9afea..8690b9e6 100644 --- a/README.md +++ b/README.md @@ -28,10 +28,14 @@ const { createProxyMiddleware } = require('http-proxy-middleware'); const app = express(); -app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true })); +app.use( + '/api', + createProxyMiddleware({ target: 'http://www.example.org/secret', changeOrigin: true }) +); app.listen(3000); -// http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar +// proxy and change the base path from "/api" to "/secret" +// http://localhost:3000/api/foo/bar -> http://www.example.org/secret/foo/bar ``` ```typescript @@ -42,9 +46,13 @@ import { createProxyMiddleware, Filter, Options, RequestHandler } from 'http-pro const app = express(); -app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true })); +app.use( + '/api', + createProxyMiddleware({ target: 'http://www.example.org/api', changeOrigin: true }) +); app.listen(3000); +// proxy and keep the same base path "/api" // http://localhost:3000/api/foo/bar -> http://www.example.org/api/foo/bar ``` @@ -57,7 +65,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option - [Install](#install) -- [Core concept](#core-concept) +- [Basic usage](#basic-usage) - [Express Server Example](#express-server-example) - [app.use(path, proxy)](#appusepath-proxy) - [Options](#options) @@ -87,7 +95,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option npm install --save-dev http-proxy-middleware ``` -## Core concept +## Basic usage Create and configure a proxy middleware with: `createProxyMiddleware(config)`. @@ -95,16 +103,15 @@ Create and configure a proxy middleware with: `createProxyMiddleware(config)`. const { createProxyMiddleware } = require('http-proxy-middleware'); const apiProxy = createProxyMiddleware({ - pathFilter: '/api', target: 'http://www.example.org', + changeOrigin: true, }); // 'apiProxy' is now ready to be used as middleware in a server. ``` -- **options.pathFilter**: Determine which requests should be proxied to the target host. - (more on [path filter](#path-filter)) - **options.target**: target host to proxy to. _(protocol + host)_ +- **options.changeOrigin**: for virtual hosted sites - see full list of [`http-proxy-middleware` configuration options](#options) @@ -117,28 +124,19 @@ An example with `express` server. const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); +const app = express(); + // proxy middleware options /** @type {import('http-proxy-middleware/dist/types').Options} */ const options = { - target: 'http://www.example.org', // target host + target: 'http://www.example.org/api', // target host with the same base path changeOrigin: true, // needed for virtual hosted sites - ws: true, // proxy websockets - pathRewrite: { - '^/api/old-path': '/api/new-path', // rewrite path - '^/api/remove/path': '/path', // remove base path - }, - router: { - // when request.headers.host == 'dev.localhost:3000', - // override target 'http://www.example.org' to 'http://localhost:8000' - 'dev.localhost:3000': 'http://localhost:8000', - }, }; // create the proxy const exampleProxy = createProxyMiddleware(options); // mount `exampleProxy` in web server -const app = express(); app.use('/api', exampleProxy); app.listen(3000); ``` @@ -149,7 +147,13 @@ 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. ```javascript -app.use('/api', createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true })); +app.use( + createProxyMiddleware({ + target: 'http://www.example.org/api', + changeOrigin: true, + pathFilter: '/api/proxy-only-this-path', + }) +); ``` `app.use` documentation: @@ -164,20 +168,11 @@ http-proxy-middleware options: ### `pathFilter` (string, []string, glob, []glob, function) -Decide which requests should be proxied; In case you are not able to use the server's [`path` parameter](http://expressjs.com/en/4x/api.html#app.use) to mount the proxy or when you need more flexibility. - -[RFC 3986 `path`](https://tools.ietf.org/html/rfc3986#section-3.3) is used in `pathFilter`. - -```ascii - foo://example.com:8042/over/there?name=ferret#nose - \_/ \______________/\_________/ \_________/ \__/ - | | | | | - scheme authority path query fragment -``` +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. + - `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** @@ -205,12 +200,13 @@ Decide which requests should be proxied; In case you are not able to use the ser /** * @return {Boolean} */ - const filter = function (path, req) { + const pathFilter = function (path, req) { return path.match('^/api') && req.method === 'GET'; }; - const apiProxy = createProxyMiddleware(filter, { + const apiProxy = createProxyMiddleware({ target: 'http://www.example.org', + pathFilter: pathFilter, }); ``` diff --git a/examples/connect/index.js b/examples/connect/index.js index 08555c31..5ab260fb 100644 --- a/examples/connect/index.js +++ b/examples/connect/index.js @@ -9,7 +9,7 @@ const { createProxyMiddleware } = require('../../dist'); // require('http-proxy- * Configure proxy middleware */ const jsonPlaceholderProxy = createProxyMiddleware({ - target: 'http://jsonplaceholder.typicode.com', + target: 'http://jsonplaceholder.typicode.com/users', changeOrigin: true, // for vhosted sites, changes host header to match to target's host logLevel: 'debug', }); diff --git a/examples/express/index.js b/examples/express/index.js index f6141c79..1070ce26 100644 --- a/examples/express/index.js +++ b/examples/express/index.js @@ -8,7 +8,7 @@ const { createProxyMiddleware } = require('../../dist'); // require('http-proxy- * Configure proxy middleware */ const jsonPlaceholderProxy = createProxyMiddleware({ - target: 'http://jsonplaceholder.typicode.com', + target: 'http://jsonplaceholder.typicode.com/users', changeOrigin: true, // for vhosted sites, changes host header to match to target's host logLevel: 'debug', }); diff --git a/recipes/async-response.md b/recipes/async-response.md index c134c374..60c2c682 100644 --- a/recipes/async-response.md +++ b/recipes/async-response.md @@ -4,7 +4,7 @@ Sometimes we need the ability to modify the response headers of the response of ```javascript const myProxy = createProxyMiddleware({ - target: 'http://www.example.com', + target: 'http://www.example.com/api', changeOrigin: true, selfHandleResponse: true, onProxyReq: (proxyReq, req, res) => { @@ -45,7 +45,7 @@ const entryMiddleware = async (req, res, next) => { }; const myProxy = createProxyMiddleware({ - target: 'http://www.example.com', + target: 'http://www.example.com/api', changeOrigin: true, selfHandleResponse: true, onProxyReq: (proxyReq, req, res) => { diff --git a/recipes/basic.md b/recipes/basic.md index d1695d2a..10357e17 100644 --- a/recipes/basic.md +++ b/recipes/basic.md @@ -6,27 +6,19 @@ This example will create a basic proxy middleware. const { createProxyMiddleware } = require('http-proxy-middleware'); const apiProxy = createProxyMiddleware({ - pathFilter: '/api', target: 'http://localhost:3000', + changeOrigin: true, }); ``` ## Alternative configuration -The proxy behavior of the following examples are **exactly** the same; Just different ways to configure it. - -```javascript -app.use(createProxyMiddleware('/api', { target: 'http://localhost:3000', changeOrigin: true })); -``` - -```javascript -app.use(createProxyMiddleware('http://localhost:3000/api', { changeOrigin: true })); -``` - ```javascript -app.use('/api', createProxyMiddleware('http://localhost:3000', { changeOrigin: true })); +app.use('/api', createProxyMiddleware({ target: 'http://localhost:3000/api', changeOrigin: true })); ``` ```javascript -app.use('/api', createProxyMiddleware({ target: 'http://localhost:3000', changeOrigin: true })); +app.use( + createProxyMiddleware({ target: 'http://localhost:3000', changeOrigin: true, pathFilter: '/api' }) +); ``` diff --git a/recipes/servers.md b/recipes/servers.md index 962ce354..9664e3bc 100644 --- a/recipes/servers.md +++ b/recipes/servers.md @@ -26,14 +26,14 @@ https://github.com/expressjs/express const express = require('express'); const { createProxyMiddleware } = require('http-proxy-middleware'); -const apiProxy = createProxyMiddleware('/api', { - target: 'http://www.example.org', +const apiProxy = createProxyMiddleware({ + target: 'http://www.example.org/api', changeOrigin: true, // for vhosted sites }); const app = express(); -app.use(apiProxy); +app.use('/api', apiProxy); app.listen(3000); ``` @@ -48,13 +48,13 @@ const http = require('http'); const connect = require('connect'); const { createProxyMiddleware } = require('http-proxy-middleware'); -const apiProxy = createProxyMiddleware('/api', { - target: 'http://www.example.org', +const apiProxy = createProxyMiddleware({ + target: 'http://www.example.org/api', changeOrigin: true, // for vhosted sites }); const app = connect(); -app.use(apiProxy); +app.use('/api', apiProxy); http.createServer(app).listen(3000); ``` @@ -88,6 +88,12 @@ export default function handler(req: NextApiRequest, res: NextApiResponse) { }); } +export const config = { + api: { + externalResolver: true, + }, +}; + // curl http://localhost:3000/api/users ``` @@ -101,9 +107,10 @@ https://github.com/BrowserSync/browser-sync const browserSync = require('browser-sync').create(); const { createProxyMiddleware } = require('http-proxy-middleware'); -const apiProxy = createProxyMiddleware('/api', { +const apiProxy = createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true, // for vhosted sites + pathFilter: '/api', }); browserSync.init({ @@ -226,9 +233,10 @@ As a `function`: ```javascript const { createProxyMiddleware } = require('http-proxy-middleware'); -const apiProxy = createProxyMiddleware('/api', { +const apiProxy = createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true, // for vhosted sites + pathFilter: '/api', }); grunt.initConfig({ @@ -262,9 +270,10 @@ gulp.task('connect', function () { connect.server({ root: ['./app'], middleware: function (connect, opt) { - const apiProxy = createProxyMiddleware('/api', { + const apiProxy = createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true, // for vhosted sites + pathFilter: '/api', }); return [apiProxy]; @@ -284,9 +293,10 @@ https://github.com/BrowserSync/grunt-browser-sync ```javascript const { createProxyMiddleware } = require('http-proxy-middleware'); -const apiProxy = createProxyMiddleware('/api', { +const apiProxy = createProxyMiddleware({ target: 'http://www.example.org', changeOrigin: true, // for vhosted sites + pathFilter: '/api', }); grunt.initConfig({ diff --git a/src/http-proxy-middleware.ts b/src/http-proxy-middleware.ts index 2a40148f..061bec46 100644 --- a/src/http-proxy-middleware.ts +++ b/src/http-proxy-middleware.ts @@ -100,8 +100,7 @@ export class HttpProxyMiddleware { * Determine whether request should be proxied. */ private shouldProxy = (pathFilter: Filter, req: Request): boolean => { - const path = (req as Request).originalUrl || req.url; - return matchPathFilter(pathFilter, path, req); + return matchPathFilter(pathFilter, req.url, req); }; /** @@ -113,10 +112,6 @@ export class HttpProxyMiddleware { * @return {Object} proxy options */ private prepareProxyRequest = async (req: Request) => { - // https://github.com/chimurai/http-proxy-middleware/issues/17 - // https://github.com/chimurai/http-proxy-middleware/issues/94 - req.url = (req as Request).originalUrl || req.url; - // store uri before it gets rewritten for logging const originalPath = req.url; const newProxyOptions = Object.assign({}, this.proxyOptions); diff --git a/src/types.ts b/src/types.ts index ad4133c9..523abb74 100644 --- a/src/types.ts +++ b/src/types.ts @@ -22,6 +22,11 @@ export interface RequestHandler { export type Filter = string | string[] | ((pathname: string, req: Request) => boolean); export interface Options extends httpProxy.ServerOptions { + /** + * Narrow down requests to proxy or not. + * Filter on {@link http.IncomingMessage.url `pathname`} which is relative to the proxy's "mounting" point in the server. + * Or use the {@link http.IncomingMessage `req`} object for more complex filtering. + */ pathFilter?: Filter; pathRewrite?: | { [regexp: string]: string } diff --git a/test/e2e/http-proxy-middleware.spec.ts b/test/e2e/http-proxy-middleware.spec.ts index 2383ca06..6437746e 100644 --- a/test/e2e/http-proxy-middleware.spec.ts +++ b/test/e2e/http-proxy-middleware.spec.ts @@ -18,10 +18,9 @@ describe('E2E http-proxy-middleware', () => { describe('pathFilter matching', () => { describe('do not proxy', () => { - const mockReq: Request = { + const mockReq: Request = { url: '/foo/bar', - originalUrl: '/foo/bar', - } as Request; + } as Request; const mockRes: Response = {} as Response; const mockNext: express.NextFunction = jest.fn(); @@ -410,7 +409,7 @@ describe('E2E http-proxy-middleware', () => { agent = request( createAppWithPath( '/api', - createProxyMiddleware({ target: `http://localhost:${mockTargetServer.port}` }) + createProxyMiddleware({ target: `http://localhost:${mockTargetServer.port}/api` }) ) ); });