Skip to content

Commit 42c495a

Browse files
committed
:fix: some bugs
1 parent ee0d025 commit 42c495a

File tree

4 files changed

+129
-125
lines changed

4 files changed

+129
-125
lines changed

lib/Proxy.js

+123-113
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
'use strict';
22

33
const utility = require('2o3t-utility');
4-
const isFunction = utility.is.function;
54
const httpProxy = require('http-proxy');
6-
const logger = require('./logger');
7-
85
const createConfig = require('./createConfig');
96
const handlers = require('./handlers');
10-
const PathRewriter = require('./path-rewriter');
117
const contextMatcher = require('./context-matcher');
8+
const PathRewriter = require('./path-rewriter');
129
const Router = require('./router');
10+
const logger = require('./logger');
11+
12+
const isFunction = utility.is.function;
13+
14+
module.exports = Proxy;
1315

14-
function PROXY(context, opts) {
16+
function Proxy(context, opts) {
1517
// https://github.com/chimurai/http-proxy-middleware/issues/57
16-
const wsUpgradeDebounced = utility.debounce(_handleUpgrade);
18+
const wsUpgradeDebounced = utility.debounce(handleUpgrade);
1719
let wsInitialized = false;
1820
const config = createConfig(context, opts);
1921
const proxyOptions = config.options;
@@ -27,86 +29,89 @@ function PROXY(context, opts) {
2729
handlers.init(proxy, proxyOptions);
2830

2931
// log errors for debug purpose
30-
proxy.on('error', _handleLogError);
32+
proxy.on('error', logError);
3133

3234
// 新增加的功能
3335
proxy.on('proxyRes', _handleProxyResBody);
3436

35-
3637
// https://github.com/chimurai/http-proxy-middleware/issues/19
3738
// expose function to upgrade externally
3839
middleware.upgrade = wsUpgradeDebounced;
3940

40-
function _handleLogError(err, req /* res */) {
41-
const hostname = (req.headers && req.headers.host) || (req.hostname || req.host); // (websocket) || (node0.10 || node 4/5)
42-
const target = proxyOptions.target.host || proxyOptions.target;
43-
const errorMessage = 'Error occurred while trying to proxy request %s from %s to %s (%s) (%s)';
44-
const errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page
41+
return middleware;
4542

46-
logger.error(errorMessage, req.url, hostname, target, err.code, errReference);
47-
}
43+
async function middleware(ctx, next) {
44+
const req = ctx.req;
45+
const res = ctx.res;
4846

49-
function _handleProxyResBody(proxyRes, req, res) {
50-
const oriWrite = res.write;
51-
const oriEnd = res.end;
52-
const proxyBody = proxyOptions.proxyBody;
53-
if (proxyBody) {
54-
const ctx = res._ctx;
55-
const jsonStrings = [];
56-
Object.assign(res, {
57-
write(chunk) {
58-
jsonStrings.push(chunk);
59-
oriWrite.apply(res, arguments);
60-
},
61-
end() {
62-
let buffer = jsonStrings.join();
63-
try {
64-
if (isFunction(proxyBody)) {
65-
const oriJSONRes = JSON.parse(buffer.toString());
66-
const handledJSONRes = proxyBody(oriJSONRes, proxyRes, req, res, ctx);
67-
buffer = new Buffer(JSON.stringify(handledJSONRes)); // 一定要转成buffer,buffer长度和string长度不一样
68-
} else {
69-
ctx.body = JSON.parse(buffer.toString());
70-
}
71-
} catch (error) {
72-
logger.warn(error);
73-
}
74-
oriEnd.apply(res, arguments);
75-
},
76-
});
47+
if (proxyOptions.ws === true) {
48+
// use initial request to access the server object to subscribe to http upgrade event
49+
catchUpgradeRequest(req.connection.server);
7750
}
78-
if (res.__resolve && isFunction(res.__resolve)) {
79-
res.__resolve(proxyRes);
51+
52+
// function middleware(req, res, next) {
53+
const proxyRes = await new Promise(resolve => {
54+
if (shouldProxy(config.context, req)) {
55+
ctx.respond = false;
56+
ctx.status = 302;
57+
const activeProxyOptions = prepareProxyRequest(req);
58+
res._ctx = ctx;
59+
res._resolve = resolve;
60+
proxy.web(req, res, activeProxyOptions);
61+
} else {
62+
resolve();
63+
}
64+
});
65+
66+
if (proxyRes) {
67+
res.proxyRes = proxyRes;
8068
}
69+
70+
await next();
8171
}
8272

83-
function _shouldProxy(req) {
84-
const context = config.context;
85-
const path = (req.originalUrl || req.url);
86-
return contextMatcher.match(context, path, req);
73+
function catchUpgradeRequest(server) {
74+
// subscribe once; don't subscribe on every request...
75+
// https://github.com/chimurai/http-proxy-middleware/issues/113
76+
if (!wsInitialized) {
77+
server.on('upgrade', wsUpgradeDebounced);
78+
wsInitialized = true;
79+
}
8780
}
8881

89-
function _handleUpgrade(req, socket, head) {
82+
function handleUpgrade(req, socket, head) {
9083
// set to initialized when used externally
91-
_wsInitialized = true;
84+
wsInitialized = true;
9285

93-
if (_shouldProxy(req)) {
86+
if (shouldProxy(config.context, req)) {
9487
const activeProxyOptions = prepareProxyRequest(req);
9588
proxy.ws(req, socket, head, activeProxyOptions);
9689
logger.system('Upgrading to WebSocket');
9790
}
9891
}
9992

100-
function _catchUpgradeRequest(server) {
101-
// subscribe once; don't subscribe on every request...
102-
// https://github.com/chimurai/http-proxy-middleware/issues/113
103-
if (!_wsInitialized) {
104-
server.on('upgrade', wsUpgradeDebounced);
105-
_wsInitialized = true;
106-
}
93+
/**
94+
* Determine whether request should be proxied.
95+
*
96+
* @private
97+
* @param {String} context [description]
98+
* @param {Object} req [description]
99+
* @return {Boolean} bool
100+
*/
101+
function shouldProxy(context, req) {
102+
const path = (req.originalUrl || req.url);
103+
return contextMatcher.match(context, path, req);
107104
}
108105

109-
function _prepareProxyRequest(req) {
106+
/**
107+
* Apply option.router and option.pathRewrite
108+
* Order matters:
109+
* Router uses original path for routing;
110+
* NOT the modified path, after it has been rewritten by pathRewrite
111+
* @param {Object} req req
112+
* @return {Object} proxy options
113+
*/
114+
function prepareProxyRequest(req) {
110115
// https://github.com/chimurai/http-proxy-middleware/issues/17
111116
// https://github.com/chimurai/http-proxy-middleware/issues/94
112117
req.url = (req.originalUrl || req.url);
@@ -123,73 +128,78 @@ function PROXY(context, opts) {
123128
return newProxyOptions;
124129
}
125130

126-
middleware.upgrade = wsUpgradeDebounced;
127-
128-
logger.system('inited...');
131+
// Modify option.target when router present.
132+
function __applyRouter(req, options) {
133+
let newTarget;
129134

130-
return middleware;
131-
132-
async function middleware(ctx, next) {
133-
const req = ctx.req;
134-
const res = ctx.res;
135+
if (options.router) {
136+
newTarget = Router.getTarget(req, options);
135137

136-
if (proxyOptions.ws === true) {
137-
// use initial request to access the server object to subscribe to http upgrade event
138-
_catchUpgradeRequest(req.connection.server);
138+
if (newTarget) {
139+
logger.system(
140+
'[Proxy] Router new target: %s -> "%s"',
141+
options.target,
142+
newTarget
143+
);
144+
options.target = newTarget;
145+
}
139146
}
147+
}
140148

141-
// function middleware(req, res, next) {
142-
const proxyRes = await new Promise(resolve => {
143-
if (_shouldProxy(req)) {
144-
ctx.respond = false;
145-
ctx.status = 302;
146-
const activeProxyOptions = _prepareProxyRequest(req);
147-
res._ctx = ctx;
148-
res.__resolve = resolve;
149+
// rewrite path
150+
function __applyPathRewrite(req, pathRewriter) {
151+
if (pathRewriter) {
152+
const path = pathRewriter(req.url, req);
149153

150-
proxy.web(req, res, activeProxyOptions);
154+
if (typeof path === 'string') {
155+
req.url = path;
151156
} else {
152-
resolve();
157+
logger.system('pathRewrite: No rewritten path found. (%s)', req.url);
153158
}
154-
});
155-
156-
if (proxyRes) {
157-
res.proxyRes = proxyRes;
158159
}
159-
160-
await next();
161160
}
162-
}
163161

164-
// Modify option.target when router present.
165-
function __applyRouter(req, options) {
166-
let newTarget;
167-
168-
if (options.router) {
169-
newTarget = Router.getTarget(req, options);
162+
function logError(err, req /* res */) {
163+
const hostname = (req.headers && req.headers.host) || (req.hostname || req.host); // (websocket) || (node0.10 || node 4/5)
164+
const target = proxyOptions.target.host || proxyOptions.target;
165+
const errorMessage = 'Error occurred while trying to proxy request %s from %s to %s (%s) (%s)';
166+
const errReference = 'https://nodejs.org/api/errors.html#errors_common_system_errors'; // link to Node Common Systems Errors page
170167

171-
if (newTarget) {
172-
logger.system(
173-
'Router new target: %s -> "%s"',
174-
options.target,
175-
newTarget
176-
);
177-
options.target = newTarget;
178-
}
168+
logger.error(errorMessage, req.url, hostname, target, err.code, errReference);
179169
}
180-
}
181170

182-
// rewrite path
183-
function __applyPathRewrite(req, pathRewriter) {
184-
if (pathRewriter) {
185-
const path = pathRewriter(req.url, req);
171+
function _handleProxyResBody(proxyRes, req, res) {
172+
const oriWrite = res.write;
173+
const oriEnd = res.end;
186174

187-
if (typeof path === 'string') {
188-
req.url = path;
189-
} else {
190-
logger.system('pathRewrite: No rewritten path found. (%s)', req.url);
175+
const proxyBody = proxyOptions.proxyBody;
176+
if (proxyBody) {
177+
const ctx = res._ctx;
178+
const jsonStrings = [];
179+
Object.assign(res, {
180+
write(chunk) {
181+
jsonStrings.push(chunk);
182+
oriWrite.apply(res, arguments);
183+
},
184+
end() {
185+
let buffer = jsonStrings.join();
186+
try {
187+
if (isFunction(proxyBody)) {
188+
const oriJSONRes = JSON.parse(buffer.toString());
189+
const handledJSONRes = proxyBody(oriJSONRes, proxyRes, req, res, ctx);
190+
buffer = new Buffer(JSON.stringify(handledJSONRes)); // 一定要转成buffer,buffer长度和string长度不一样
191+
} else {
192+
ctx.body = JSON.parse(buffer.toString());
193+
}
194+
} catch (error) {
195+
logger.warn(error);
196+
}
197+
oriEnd.apply(res, arguments);
198+
},
199+
});
200+
}
201+
if (res._resolve && isFunction(res._resolve)) {
202+
res._resolve(proxyRes);
191203
}
192204
}
193205
}
194-
195-
module.exports = PROXY;

lib/handlers.js

+1-7
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ function getProxyEventHandlers(opts) {
3030
// all handlers for the http-proxy events are prefixed with 'on'.
3131
// loop through options and try to find these handlers
3232
// and add them to the handlers object for subscription in init().
33-
const eventName = 'on' + defaultCamelize2Str(event);
33+
const eventName = utility.defaultCamelize2Str('on_' + event, 'camel');
3434
const fnHandler = opts[eventName];
3535

3636
if (isFunction(fnHandler)) {
@@ -77,9 +77,3 @@ function logClose(/* req, socket, head */) {
7777
// view disconnected websocket connections
7878
logger.system('Client disconnected');
7979
}
80-
81-
function defaultCamelize2Str(str) {
82-
let first = str[0];
83-
first = first.toLowerCase();
84-
return first + str.substring(1);
85-
}

lib/router.js

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
'use strict';
22

3-
const utility = require('2o3t-utility');
3+
const _ = require('lodash');
44
const logger = require('./logger');
55

66
module.exports = {
@@ -11,9 +11,9 @@ function getTarget(req, config) {
1111
let newTarget;
1212
const router = config.router;
1313

14-
if (utility.isPlainObject(router)) {
14+
if (_.isPlainObject(router)) {
1515
newTarget = getTargetFromProxyTable(req, router);
16-
} else if (utility.isFunction(router)) {
16+
} else if (_.isFunction(router)) {
1717
newTarget = router(req);
1818
}
1919

@@ -27,7 +27,7 @@ function getTargetFromProxyTable(req, table) {
2727

2828
const hostAndPath = host + path;
2929

30-
utility.forIn(table, function(value, key) {
30+
_.forIn(table, function(value, key) {
3131
if (containsPath(key)) {
3232
if (hostAndPath.indexOf(key) > -1) {
3333
// match 'localhost:3000/api'

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@2o3t/koa2-proxy-middleware",
3-
"version": "0.0.3",
3+
"version": "0.0.4",
44
"description": "http proxy middleware for koa2",
55
"main": "index.js",
66
"scripts": {

0 commit comments

Comments
 (0)