Skip to content

Commit

Permalink
refactor(handlers): refactor to plugins [BREAKING CHANGE] (#745)
Browse files Browse the repository at this point in the history
* feat(debug): debug proxy server errors

* refactor(handlers): migrate error, response and log handlers to plugins [BREAKING CHANGE]

* refactor(proxy events): refactor to proxy-events plugin [BREAKING CHANGE]
  • Loading branch information
chimurai authored Apr 11, 2022
1 parent 7341704 commit 33f9f5a
Show file tree
Hide file tree
Showing 22 changed files with 401 additions and 403 deletions.
35 changes: 26 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -274,8 +274,8 @@ router: async function(req) {
### `plugins` (Array)

```js
const simpleRequestLogger = (proxy, options) => {
proxy.on('proxyReq', (proxyReq, req, res) => {
const simpleRequestLogger = (proxyServer, options) => {
proxyServer.on('proxyReq', (proxyReq, req, res) => {
console.log(`[HPM] [${req.method}] ${req.url}`); // outputs: [HPM] GET /users
});
},
Expand Down Expand Up @@ -323,9 +323,26 @@ function logProvider(provider) {

## `http-proxy` events

Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events):
Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#listening-for-proxy-events) with the `on` option:

- **option.onError**: function, subscribe to http-proxy's `error` event for custom error handling.
```js
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.

```javascript
function onError(err, req, res, target) {
Expand All @@ -336,7 +353,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
}
```

- **option.onProxyRes**: function, subscribe to http-proxy's `proxyRes` event.
- **option.on.proxyRes**: function, subscribe to http-proxy's `proxyRes` event.

```javascript
function onProxyRes(proxyRes, req, res) {
Expand All @@ -345,7 +362,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
}
```

- **option.onProxyReq**: function, subscribe to http-proxy's `proxyReq` event.
- **option.on.proxyReq**: function, subscribe to http-proxy's `proxyReq` event.

```javascript
function onProxyReq(proxyReq, req, res) {
Expand All @@ -355,7 +372,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
}
```

- **option.onProxyReqWs**: function, subscribe to http-proxy's `proxyReqWs` event.
- **option.on.proxyReqWs**: function, subscribe to http-proxy's `proxyReqWs` event.

```javascript
function onProxyReqWs(proxyReq, req, socket, options, head) {
Expand All @@ -364,7 +381,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
}
```

- **option.onOpen**: function, subscribe to http-proxy's `open` event.
- **option.on.open**: function, subscribe to http-proxy's `open` event.

```javascript
function onOpen(proxySocket) {
Expand All @@ -373,7 +390,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
}
```

- **option.onClose**: function, subscribe to http-proxy's `close` event.
- **option.on.close**: function, subscribe to http-proxy's `close` event.

```javascript
function onClose(res, socket, head) {
Expand Down
28 changes: 15 additions & 13 deletions examples/response-interceptor/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,23 +45,25 @@ const jsonPlaceholderProxy = createProxyMiddleware({
},
changeOrigin: true, // for vhosted sites, changes host header to match to target's host
selfHandleResponse: true, // manually call res.end(); IMPORTANT: res.end() is called internally by responseInterceptor()
onProxyRes: responseInterceptor(async (buffer, proxyRes, req, res) => {
// log original request and proxied request info
const exchange = `[DEBUG] ${req.method} ${req.path} -> ${proxyRes.req.protocol}//${proxyRes.req.host}${proxyRes.req.path} [${proxyRes.statusCode}]`;
console.log(exchange);
on: {
proxyRes: responseInterceptor(async (buffer, proxyRes, req, res) => {
// log original request and proxied request info
const exchange = `[DEBUG] ${req.method} ${req.path} -> ${proxyRes.req.protocol}//${proxyRes.req.host}${proxyRes.req.path} [${proxyRes.statusCode}]`;
console.log(exchange);

// log original response
// console.log(`[DEBUG] original response:\n${buffer.toString('utf8')}`);
// log original response
// console.log(`[DEBUG] original response:\n${buffer.toString('utf8')}`);

// set response content-type
res.setHeader('content-type', 'application/json; charset=utf-8');
// set response content-type
res.setHeader('content-type', 'application/json; charset=utf-8');

// set response status code
res.statusCode = 418;
// set response status code
res.statusCode = 418;

// return a complete different response
return JSON.stringify(favoriteFoods);
}),
// return a complete different response
return JSON.stringify(favoriteFoods);
}),
},
logLevel: 'debug',
});

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"devDependencies": {
"@commitlint/cli": "16.2.1",
"@commitlint/config-conventional": "16.2.1",
"@types/debug": "4.1.7",
"@types/express": "4.17.13",
"@types/is-glob": "4.0.2",
"@types/jest": "27.4.0",
Expand Down Expand Up @@ -85,6 +86,7 @@
},
"dependencies": {
"@types/http-proxy": "^1.17.8",
"debug": "^4.3.4",
"http-proxy": "^1.18.1",
"is-glob": "^4.0.1",
"is-plain-obj": "^3.0.0",
Expand Down
30 changes: 21 additions & 9 deletions recipes/proxy-events.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Proxy Events

Subscribe to [`http-proxy`](https://github.com/nodejitsu/node-http-proxy) [![GitHub stars](https://img.shields.io/github/stars/nodejitsu/node-http-proxy.svg?style=social&label=Star)](https://github.com/nodejitsu/node-http-proxy) events: `error`, `proxyReq`, `proxyReqWs`, `proxyRes`, `open`, `close`.
Subscribe to [`http-proxy`](https://github.com/nodejitsu/node-http-proxy) [![GitHub stars](https://img.shields.io/github/stars/nodejitsu/node-http-proxy.svg?style=social&label=Star)](https://github.com/nodejitsu/node-http-proxy) events: `error`, `proxyReq`, `proxyReqWs`, `proxyRes`, `open`, `close`, `start`, `end`, `econnreset`.

## onError
## on.error

Subscribe to http-proxy's [error event](https://www.npmjs.com/package/http-proxy#listening-for-proxy-events).

Expand All @@ -14,12 +14,15 @@ const onError = function (err, req, res) {
console.log('And we are reporting a custom error message.');
};

const options = { target: 'http://localhost:3000', onError: onError };
const options = {
target: 'http://localhost:3000',
on: { 'error', onError }
};

const apiProxy = createProxyMiddleware(options);
```

## onProxyReq
## on.proxyReq

Subscribe to http-proxy's [proxyReq event](https://www.npmjs.com/package/http-proxy#listening-for-proxy-events).

Expand All @@ -31,12 +34,15 @@ const onProxyReq = function (proxyReq, req, res) {
proxyReq.setHeader('x-added', 'foobar');
};

const options = { target: 'http://localhost:3000', onProxyReq: onProxyReq };
const options = {
target: 'http://localhost:3000',
on: { 'proxyReq', onProxyReq }
};

const apiProxy = createProxyMiddleware(options);
```

## onProxyReqWs
## on.proxyReqWs

Subscribe to http-proxy's [proxyReqWs event](https://www.npmjs.com/package/http-proxy#listening-for-proxy-events).

Expand All @@ -48,12 +54,15 @@ const onProxyReqWs = function (proxyReq, req, socket, options, head) {
proxyReq.setHeader('X-Special-Proxy-Header', 'foobar');
};

const options = { target: 'http://localhost:3000', onProxyReqWs: onProxyReqWs };
const options = {
target: 'http://localhost:3000',
on: { 'proxyReqWs', onProxyReqWs }
};

const apiProxy = createProxyMiddleware(options);
```

## onProxyRes
## on.proxyRes

Subscribe to http-proxy's [proxyRes event](https://www.npmjs.com/package/http-proxy#listening-for-proxy-events).

Expand All @@ -68,7 +77,10 @@ const onProxyRes = function (proxyRes, req, res) {
delete proxyRes.headers['x-removed'];
};

const options = { target: 'http://localhost:3000', onProxyRes: onProxyRes };
const options = {
target: 'http://localhost:3000',
on: { 'proxyRes', onProxyRes }
};

const apiProxy = createProxyMiddleware(options);
```
87 changes: 0 additions & 87 deletions src/_handlers.ts

This file was deleted.

6 changes: 6 additions & 0 deletions src/debug.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import * as createDebug from 'debug';

/**
* Debug instance with the given namespace: hpm
*/
export const debug = createDebug('hpm');
38 changes: 14 additions & 24 deletions src/http-proxy-middleware.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,17 @@
import type * as https from 'https';
import type * as express from 'express';
import type { Request, RequestHandler, Response, Options, Filter } from './types';
import type { Request, RequestHandler, Options, Filter } from './types';
import * as httpProxy from 'http-proxy';
import { verifyConfig } from './configuration';
import { matchPathFilter } from './path-filter';
import * as handlers from './_handlers';
import { getArrow, getInstance } from './logger';
import * as PathRewriter from './path-rewriter';
import * as Router from './router';
import {
debugProxyErrorsPlugin,
createLoggerPlugin,
errorResponsePlugin,
proxyEventsPlugin,
} from './plugins/default';

export class HttpProxyMiddleware {
private logger = getInstance();
Expand All @@ -29,12 +33,6 @@ export class HttpProxyMiddleware {

this.pathRewriter = PathRewriter.createPathRewriter(this.proxyOptions.pathRewrite); // returns undefined when "pathRewrite" is not provided

// attach handler to http-proxy events
handlers.init(this.proxy, this.proxyOptions);

// log errors for debug purpose
this.proxy.on('error', this.logError);

// https://github.com/chimurai/http-proxy-middleware/issues/19
// expose function to upgrade externally
this.middleware.upgrade = (req, socket, head) => {
Expand Down Expand Up @@ -82,8 +80,14 @@ export class HttpProxyMiddleware {
};

private registerPlugins(proxy: httpProxy, options: Options) {
const defaultPlugins = [
debugProxyErrorsPlugin,
proxyEventsPlugin,
createLoggerPlugin(),
errorResponsePlugin,
];
const plugins = options.plugins ?? [];
plugins.forEach((plugin) => plugin(proxy, options));
[...defaultPlugins, ...plugins].forEach((plugin) => plugin(proxy, options));
}

private catchUpgradeRequest = (server: https.Server) => {
Expand Down Expand Up @@ -175,18 +179,4 @@ export class HttpProxyMiddleware {
}
}
};

private logError = (err, req: Request, res: Response, target?) => {
const hostname =
req.headers?.host ||
(req as Request<express.Request>).hostname ||
(req as Request<express.Request>).host; // (websocket) || (node0.10 || node 4/5)
const requestHref = `${hostname}${req.url}`;
const targetHref = `${target?.href}`; // target is undefined when websocket errors

const errorMessage = '[HPM] Error occurred while proxying request %s to %s [%s] (%s)';
const errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page

this.logger.error(errorMessage, requestHref, targetHref, err.code || err, errReference);
};
}
Loading

0 comments on commit 33f9f5a

Please sign in to comment.