http-proxy-middleware 1.1.2-alpha.1 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/README.md +38 -3
- package/dist/{handlers.d.ts → _handlers.d.ts} +0 -0
- package/dist/{handlers.js → _handlers.js} +0 -0
- package/dist/handlers/index.d.ts +1 -0
- package/dist/handlers/index.js +13 -0
- package/dist/handlers/public.d.ts +1 -0
- package/dist/handlers/public.js +5 -0
- package/dist/handlers/response-interceptor.d.ts +12 -0
- package/dist/handlers/response-interceptor.js +72 -0
- package/dist/http-proxy-middleware.js +9 -8
- package/dist/index.d.ts +1 -0
- package/dist/index.js +11 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [v1.2.0](https://github.com/chimurai/http-proxy-middleware/releases/tag/v1.2.0)
|
|
4
|
+
|
|
5
|
+
- feat(handler): response interceptor ([#520](https://github.com/chimurai/http-proxy-middleware/pull/520))
|
|
6
|
+
- fix(log error): handle undefined target when websocket errors ([#527](https://github.com/chimurai/http-proxy-middleware/pull/527))
|
|
7
|
+
|
|
8
|
+
## [v1.1.2](https://github.com/chimurai/http-proxy-middleware/releases/tag/v1.1.2)
|
|
9
|
+
|
|
10
|
+
- fix(log error): handle optional target ([#523](https://github.com/chimurai/http-proxy-middleware/pull/523))
|
|
11
|
+
|
|
3
12
|
## [v1.1.1](https://github.com/chimurai/http-proxy-middleware/releases/tag/v1.1.1)
|
|
4
13
|
|
|
5
14
|
- fix(error handler): re-throw http-proxy missing target error ([#517](https://github.com/chimurai/http-proxy-middleware/pull/517))
|
package/README.md
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# http-proxy-middleware
|
|
2
2
|
|
|
3
|
-
[](https://github.com/chimurai/http-proxy-middleware/actions?query=branch%3Amaster)
|
|
4
4
|
[](https://coveralls.io/r/chimurai/http-proxy-middleware)
|
|
5
5
|
[](https://david-dm.org/chimurai/http-proxy-middleware#info=dependencies)
|
|
6
6
|
[](https://snyk.io/test/npm/http-proxy-middleware)
|
|
7
|
-
[](https://www.npmjs.com/package/http-proxy-middleware)
|
|
8
8
|
|
|
9
9
|
Node.js proxying made simple. Configure proxy middleware with ease for [connect](https://github.com/senchalabs/connect), [express](https://github.com/strongloop/express), [browser-sync](https://github.com/BrowserSync/browser-sync) and [many more](#compatible-servers).
|
|
10
10
|
|
|
@@ -69,6 +69,7 @@ _All_ `http-proxy` [options](https://github.com/nodejitsu/node-http-proxy#option
|
|
|
69
69
|
- [app.use\(path, proxy\)](#appusepath-proxy)
|
|
70
70
|
- [WebSocket](#websocket)
|
|
71
71
|
- [External WebSocket upgrade](#external-websocket-upgrade)
|
|
72
|
+
- [Intercept and manipulate responses](#intercept-and-manipulate-responses)
|
|
72
73
|
- [Working examples](#working-examples)
|
|
73
74
|
- [Recipes](#recipes)
|
|
74
75
|
- [Compatible servers](#compatible-servers)
|
|
@@ -298,7 +299,7 @@ Subscribe to [http-proxy events](https://github.com/nodejitsu/node-http-proxy#li
|
|
|
298
299
|
- **option.onError**: function, subscribe to http-proxy's `error` event for custom error handling.
|
|
299
300
|
|
|
300
301
|
```javascript
|
|
301
|
-
function onError(err, req, res) {
|
|
302
|
+
function onError(err, req, res, target) {
|
|
302
303
|
res.writeHead(500, {
|
|
303
304
|
'Content-Type': 'text/plain',
|
|
304
305
|
});
|
|
@@ -481,6 +482,39 @@ const server = app.listen(3000);
|
|
|
481
482
|
server.on('upgrade', wsProxy.upgrade); // <-- subscribe to http 'upgrade'
|
|
482
483
|
```
|
|
483
484
|
|
|
485
|
+
## Intercept and manipulate responses
|
|
486
|
+
|
|
487
|
+
Intercept responses from upstream with `responseInterceptor`. (Make sure to set `selfHandleResponse: true`)
|
|
488
|
+
|
|
489
|
+
Responses which are compressed with `brotli`, `gzip` and `deflate` will be decompressed automatically. The response will be returned as `buffer` ([docs](https://nodejs.org/api/buffer.html)) which you can manipulate.
|
|
490
|
+
|
|
491
|
+
With `buffer`, response manipulation is not limited to text responses (html/css/js, etc...); image manipulation will be possible too. ([example](https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/response-interceptor.md#manipulate-image-response))
|
|
492
|
+
|
|
493
|
+
NOTE: `responseInterceptor` disables streaming of target's response.
|
|
494
|
+
|
|
495
|
+
Example:
|
|
496
|
+
|
|
497
|
+
```javascript
|
|
498
|
+
const { createProxyMiddleware, responseInterceptor } = require('http-proxy-middleware');
|
|
499
|
+
|
|
500
|
+
const proxy = createProxyMiddleware({
|
|
501
|
+
/**
|
|
502
|
+
* IMPORTANT: avoid res.end being called automatically
|
|
503
|
+
**/
|
|
504
|
+
selfHandleResponse: true, // res.end() will be called internally by responseInterceptor()
|
|
505
|
+
|
|
506
|
+
/**
|
|
507
|
+
* Intercept response and replace 'Hello' with 'Goodbye'
|
|
508
|
+
**/
|
|
509
|
+
onProxyRes: responseInterceptor(async (responseBuffer, proxyRes, req, res) => {
|
|
510
|
+
const response = responseBuffer.toString('utf-8'); // convert buffer to string
|
|
511
|
+
return response.replace('Hello', 'Goodbye'); // manipulate response and return the result
|
|
512
|
+
}),
|
|
513
|
+
});
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
Check out [interception recipes](https://github.com/chimurai/http-proxy-middleware/blob/master/recipes/response-interceptor.md#readme) for more examples.
|
|
517
|
+
|
|
484
518
|
## Working examples
|
|
485
519
|
|
|
486
520
|
View and play around with [working examples](https://github.com/chimurai/http-proxy-middleware/tree/master/examples).
|
|
@@ -489,6 +523,7 @@ View and play around with [working examples](https://github.com/chimurai/http-pr
|
|
|
489
523
|
- express ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/express/index.js))
|
|
490
524
|
- connect ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/connect/index.js))
|
|
491
525
|
- WebSocket ([example source](https://github.com/chimurai/http-proxy-middleware/tree/master/examples/websocket/index.js))
|
|
526
|
+
- Response Manipulation ([example source](https://github.com/chimurai/http-proxy-middleware/blob/master/examples/response-interceptor/index.js))
|
|
492
527
|
|
|
493
528
|
## Recipes
|
|
494
529
|
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './public';
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
12
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
13
|
+
__exportStar(require("./public"), exports);
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { responseInterceptor } from './response-interceptor';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.responseInterceptor = void 0;
|
|
4
|
+
var response_interceptor_1 = require("./response-interceptor");
|
|
5
|
+
Object.defineProperty(exports, "responseInterceptor", { enumerable: true, get: function () { return response_interceptor_1.responseInterceptor; } });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import type * as http from 'http';
|
|
3
|
+
declare type Interceptor = (buffer: Buffer, proxyRes: http.IncomingMessage, req: http.IncomingMessage, res: http.ServerResponse) => Promise<Buffer | string>;
|
|
4
|
+
/**
|
|
5
|
+
* Intercept responses from upstream.
|
|
6
|
+
* Automatically decompress (deflate, gzip, brotli).
|
|
7
|
+
* Give developer the opportunity to modify intercepted Buffer and http.ServerResponse
|
|
8
|
+
*
|
|
9
|
+
* NOTE: must set options.selfHandleResponse=true (prevent automatic call of res.end())
|
|
10
|
+
*/
|
|
11
|
+
export declare function responseInterceptor(interceptor: Interceptor): (proxyRes: http.IncomingMessage, req: http.IncomingMessage, res: http.ServerResponse) => Promise<void>;
|
|
12
|
+
export {};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.responseInterceptor = void 0;
|
|
13
|
+
const zlib = require("zlib");
|
|
14
|
+
/**
|
|
15
|
+
* Intercept responses from upstream.
|
|
16
|
+
* Automatically decompress (deflate, gzip, brotli).
|
|
17
|
+
* Give developer the opportunity to modify intercepted Buffer and http.ServerResponse
|
|
18
|
+
*
|
|
19
|
+
* NOTE: must set options.selfHandleResponse=true (prevent automatic call of res.end())
|
|
20
|
+
*/
|
|
21
|
+
function responseInterceptor(interceptor) {
|
|
22
|
+
return function proxyRes(proxyRes, req, res) {
|
|
23
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
24
|
+
const originalProxyRes = proxyRes;
|
|
25
|
+
let buffer = Buffer.from('', 'utf8');
|
|
26
|
+
// decompress proxy response
|
|
27
|
+
const _proxyRes = decompress(proxyRes, proxyRes.headers['content-encoding']);
|
|
28
|
+
// concat data stream
|
|
29
|
+
_proxyRes.on('data', (chunk) => (buffer = Buffer.concat([buffer, chunk])));
|
|
30
|
+
_proxyRes.on('end', () => __awaiter(this, void 0, void 0, function* () {
|
|
31
|
+
// set original content type from upstream
|
|
32
|
+
res.setHeader('content-type', originalProxyRes.headers['content-type'] || '');
|
|
33
|
+
// call interceptor with intercepted response (buffer)
|
|
34
|
+
const interceptedBuffer = Buffer.from(yield interceptor(buffer, originalProxyRes, req, res));
|
|
35
|
+
// set correct content-length (with double byte character support)
|
|
36
|
+
res.setHeader('content-length', Buffer.byteLength(interceptedBuffer, 'utf8'));
|
|
37
|
+
res.write(interceptedBuffer);
|
|
38
|
+
res.end();
|
|
39
|
+
}));
|
|
40
|
+
_proxyRes.on('error', (error) => {
|
|
41
|
+
res.end(`Error fetching proxied request: ${error.message}`);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
exports.responseInterceptor = responseInterceptor;
|
|
47
|
+
/**
|
|
48
|
+
* Streaming decompression of proxy response
|
|
49
|
+
* source: https://github.com/apache/superset/blob/9773aba522e957ed9423045ca153219638a85d2f/superset-frontend/webpack.proxy-config.js#L116
|
|
50
|
+
*/
|
|
51
|
+
function decompress(proxyRes, contentEncoding) {
|
|
52
|
+
let _proxyRes = proxyRes;
|
|
53
|
+
let decompress;
|
|
54
|
+
switch (contentEncoding) {
|
|
55
|
+
case 'gzip':
|
|
56
|
+
decompress = zlib.createGunzip();
|
|
57
|
+
break;
|
|
58
|
+
case 'br':
|
|
59
|
+
decompress = zlib.createBrotliDecompress();
|
|
60
|
+
break;
|
|
61
|
+
case 'deflate':
|
|
62
|
+
decompress = zlib.createInflate();
|
|
63
|
+
break;
|
|
64
|
+
default:
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (decompress) {
|
|
68
|
+
_proxyRes.pipe(decompress);
|
|
69
|
+
_proxyRes = decompress;
|
|
70
|
+
}
|
|
71
|
+
return _proxyRes;
|
|
72
|
+
}
|
|
@@ -13,7 +13,7 @@ exports.HttpProxyMiddleware = void 0;
|
|
|
13
13
|
const httpProxy = require("http-proxy");
|
|
14
14
|
const config_factory_1 = require("./config-factory");
|
|
15
15
|
const contextMatcher = require("./context-matcher");
|
|
16
|
-
const handlers = require("./
|
|
16
|
+
const handlers = require("./_handlers");
|
|
17
17
|
const logger_1 = require("./logger");
|
|
18
18
|
const PathRewriter = require("./path-rewriter");
|
|
19
19
|
const Router = require("./router");
|
|
@@ -135,14 +135,15 @@ class HttpProxyMiddleware {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
});
|
|
138
|
-
this.logError = (err, req, res) =>
|
|
139
|
-
|
|
140
|
-
const
|
|
141
|
-
const
|
|
142
|
-
const
|
|
138
|
+
this.logError = (err, req, res, target) => {
|
|
139
|
+
var _a;
|
|
140
|
+
const hostname = ((_a = req.headers) === null || _a === void 0 ? void 0 : _a.host) || req.hostname || req.host; // (websocket) || (node0.10 || node 4/5)
|
|
141
|
+
const requestHref = `${hostname}${req.url}`;
|
|
142
|
+
const targetHref = `${target === null || target === void 0 ? void 0 : target.href}`; // target is undefined when websocket errors
|
|
143
|
+
const errorMessage = '[HPM] Error occurred while proxying request %s to %s [%s] (%s)';
|
|
143
144
|
const errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page
|
|
144
|
-
this.logger.error(errorMessage,
|
|
145
|
-
}
|
|
145
|
+
this.logger.error(errorMessage, requestHref, targetHref, err.code || err, errReference);
|
|
146
|
+
};
|
|
146
147
|
this.config = config_factory_1.createConfig(context, opts);
|
|
147
148
|
this.proxyOptions = this.config.options;
|
|
148
149
|
// create proxy
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
|
|
5
|
+
}) : (function(o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
o[k2] = m[k];
|
|
8
|
+
}));
|
|
9
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
10
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
11
|
+
};
|
|
2
12
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
13
|
exports.createProxyMiddleware = void 0;
|
|
4
14
|
const http_proxy_middleware_1 = require("./http-proxy-middleware");
|
|
@@ -7,3 +17,4 @@ function createProxyMiddleware(context, options) {
|
|
|
7
17
|
return middleware;
|
|
8
18
|
}
|
|
9
19
|
exports.createProxyMiddleware = createProxyMiddleware;
|
|
20
|
+
__exportStar(require("./handlers"), exports);
|
package/package.json
CHANGED