Skip to content

Commit 0b85d13

Browse files
committed
update v2.0.0
1 parent 2fec684 commit 0b85d13

24 files changed

+1353
-290
lines changed

models/caches.js

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: Sky.Sun
33
* @Date: 2018-04-18 15:51:26
44
* @Last Modified by: Sky.Sun
5-
* @Last Modified time: 2018-07-11 12:09:29
5+
* @Last Modified time: 2019-05-15 14:18:46
66
*/
77
const mongoose = require('../db').mongoose;
88
const cacheSchemaObj = {
@@ -23,6 +23,11 @@ const cacheSchemaObj = {
2323
required: true
2424
},
2525

26+
// 要匹配的请求参数
27+
params: {
28+
type: String
29+
},
30+
2631
// 要匹配的域名ID
2732
domainId: {
2833
type: String
@@ -33,7 +38,7 @@ const cacheSchemaObj = {
3338
type: String,
3439
required: true
3540
},
36-
41+
3742
// 缓存自定义键
3843
keyContent: {
3944
type: String
@@ -80,4 +85,4 @@ const cacheSchemaObj = {
8085
const cacheSchema = mongoose.Schema(cacheSchemaObj);
8186

8287
exports.cacheSchemaObj = cacheSchemaObj;
83-
exports.cacheModel = mongoose.model('caches', cacheSchema);
88+
exports.cacheModel = mongoose.model('caches', cacheSchema);

models/permissions.js

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: Sky.Sun
33
* @Date: 2018-03-01 11:31:49
44
* @Last Modified by: Sky.Sun
5-
* @Last Modified time: 2018-07-11 14:27:57
5+
* @Last Modified time: 2019-05-15 14:18:00
66
*/
77
const mongoose = require('../db').mongoose;
88
const permissionSchemaObj = {
@@ -29,6 +29,11 @@ const permissionSchemaObj = {
2929
required: true
3030
},
3131

32+
// 要匹配的请求参数
33+
params: {
34+
type: String
35+
},
36+
3237
// 要匹配的域名ID
3338
domainId: {
3439
type: String

models/routes.js

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: Sky.Sun
33
* @Date: 2018-02-07 11:42:27
44
* @Last Modified by: Sky.Sun
5-
* @Last Modified time: 2018-07-11 12:10:22
5+
* @Last Modified time: 2019-05-15 14:17:39
66
*/
77
const mongoose = require('../db').mongoose;
88
const routeSchemaObj = {
@@ -23,6 +23,11 @@ const routeSchemaObj = {
2323
required: true
2424
},
2525

26+
// 要匹配的请求参数
27+
params: {
28+
type: String
29+
},
30+
2631
// 要匹配的域名ID
2732
domainId: {
2833
type: String
@@ -51,6 +56,11 @@ const routeSchemaObj = {
5156
required: true
5257
},
5358

59+
// 当处理方式是forward,且content值为url时,此字段存储要转发到的地址
60+
forwardUrl: {
61+
type: String
62+
},
63+
5464
// 自定义响应的状态码
5565
customStatus: {
5666
type: String

server.js

Lines changed: 112 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* @Author: Sky.Sun
33
* @Date: 2018-01-17 16:07:30
44
* @Last Modified by: Sky.Sun
5-
* @Last Modified time: 2019-05-15 11:15:16
5+
* @Last Modified time: 2019-06-12 16:22:08
66
*/
77
const express = require('express');
88
const app = express();
@@ -76,71 +76,132 @@ process.on('unhandledRejection', reason => {
7676
schedule.startJob();
7777

7878
/**
79-
* 生成一个筛选函数
80-
* 筛选函数返回是否能找到对应的规则
79+
* 从所配规则中,找出最匹配的那个规则并返回
8180
*
82-
* @param {object} req - 请求
83-
* @returns {function} - 筛选函数
81+
* @param {*} rules - 规则数组
82+
* @param {*} req - 请求对象
8483
*/
85-
function routeFilter(req) {
86-
return item => {
84+
function getMatchedRule (rules, req) {
85+
if (!rules || !rules.length) {
86+
return null;
87+
}
88+
89+
// 临时匹配数组,最多只可能有2条,其中开头匹配最多1条,正则匹配最多1条
90+
const arr = [];
91+
92+
// 使用for而非forEach是为了方便continue流程控制
93+
for (let i = 0; i < rules.length; i++) {
94+
const item = rules[i];
8795
if (item.active && !item.deleted) {
88-
// 首先检测域名是否一致
96+
// 匹配域名
8997
let domainMatch = false;
9098
if (!item.domainId) {
9199
domainMatch = true;
92100
} else {
93-
const domain = settings.getDomains().find(t => t.id === item.domainId);
94-
if (domain) {
101+
const domains = settings.getDomains();
102+
const domain = domains.find(t => t.id === item.domainId);
103+
if (!domain) {
104+
domainMatch = false;
105+
} else {
95106
domainMatch = req.hostname === domain.domainPath;
96-
if (isDebug && req.query.__domain === domain.domainPath) {
97-
// 链接参数中的 __domain 与规则一致也认为匹配成功,方便本地调试
98-
domainMatch = true;
99-
}
100107
}
101108
}
102109
if (!domainMatch) {
103-
return false;
110+
continue;
104111
}
105112

106-
// 判断请求方式
113+
// 匹配请求方式
107114
if (item.method && item.method.toUpperCase() !== req.method.toUpperCase()) {
108-
return false;
115+
continue;
116+
}
117+
118+
// 匹配请求参数
119+
if (item.params) {
120+
const query = req.query;
121+
const body = req.body;
122+
const cookies = req.cookies;
123+
try {
124+
if (!Boolean(eval(item.params))) {
125+
continue;
126+
}
127+
} catch (err) {
128+
logger.error('匹配参数异常!params:', item.params);
129+
continue;
130+
}
109131
}
110132

133+
// 匹配路径
111134
let reqPath = req.path;
112135
let uri = item.uri;
136+
if (item.type !== 'regexp') {
137+
// 对于没有后缀的 req.path,尝试加上末尾斜杠(/)后再判断,提高容错
138+
if (!path.extname(reqPath) && reqPath.substr(-1) !== '/') {
139+
reqPath = `${reqPath}/`;
140+
}
113141

114-
// 正则匹配
115-
if (item.type === 'regexp') {
116-
uri = new RegExp(uri);
117-
return uri.test(reqPath);
118-
}
119-
120-
// 对于没有后缀的 req.path,尝试加上末尾斜杠(/)后再判断,提高容错
121-
if (!path.extname(reqPath) && reqPath.substr(-1) !== '/') {
122-
reqPath = `${reqPath}/`;
123-
}
142+
// 对于没有后缀的 uri,尝试加上末尾斜杠(/)后再判断,提高容错
143+
if (!path.extname(uri) && uri.substr(-1) !== '/') {
144+
uri = `${uri}/`;
145+
}
124146

125-
// 对于没有后缀的 uri,尝试加上末尾斜杠(/)后再判断,提高容错
126-
if (!path.extname(uri) && uri.substr(-1) !== '/') {
127-
uri = `${uri}/`;
147+
if (item.type === 'exact') {
148+
// 精确匹配
149+
if (reqPath === uri) {
150+
// 精确匹配成功的话,终止遍历,直接返回结果
151+
return item;
152+
}
153+
continue;
154+
} else {
155+
// 开头匹配
156+
if (reqPath.startsWith(uri)) {
157+
// 开头匹配成功的话,看数组中是否已经存在开头匹配的项了
158+
const existsIdx = arr.findIndex(t => t.type === 'start');
159+
if (existsIdx >= 0) {
160+
// 如果存在,再比较uri长度
161+
let existsItemUri = arr[existsIdx].uri;
162+
if (!path.extname(existsItemUri) && existsItemUri.substr(-1) !== '/') {
163+
existsItemUri = `${existsItemUri}/`;
164+
}
165+
if (uri.length > existsItemUri.length) {
166+
// 删除之前存在的规则,并在末尾存入uri更长的那条规则
167+
arr.splice(existsIdx, 1);
168+
arr.push(item);
169+
}
170+
} else {
171+
// 不存在,直接加入
172+
arr.push(item);
173+
}
174+
}
175+
}
176+
} else {
177+
// 正则表达式匹配
178+
uri = new RegExp(uri);
179+
if (uri.test(reqPath)) {
180+
// 如果匹配成功,看下数组中是否已经存在正则匹配的项,如果不存在才存入
181+
if (!arr.some(t => t.type === 'regexp')) {
182+
arr.push(item);
183+
}
184+
}
128185
}
186+
}
187+
}
129188

130-
// 精确匹配
131-
if (item.type === 'exact') {
132-
return reqPath === uri;
133-
}
189+
// 精确匹配成功会直接返回,所以走到这一步时,一定只剩下开头匹配和正则匹配了,数组长度只可能有3种情况:0, 1, 2
190+
if (!arr.length) {
191+
return null;
192+
}
193+
if (arr.length === 1) {
194+
return arr[0];
195+
}
134196

135-
// 匹配开头
136-
if (item.type === 'start') {
137-
return reqPath.startsWith(uri);
138-
}
197+
// 数组长度为2,说明一定是1条开头匹配,1条正则匹配,此时需要再判断下开头匹配是否是兜底规则
198+
const bottomRuleIdx = arr.findIndex(t => (t.type === 'start' && t.uri === '/'));
199+
if (bottomRuleIdx >= 0) {
200+
arr.splice(bottomRuleIdx, 1);
201+
}
139202

140-
return false;
141-
}
142-
return false;
143-
};
203+
// 此时,一定不存在兜底规则了,则取数组中的第一项返回,因为第一项规则必定是排序靠前的
204+
return arr[0];
144205
}
145206

146207
/**
@@ -185,15 +246,11 @@ app.use((req, res, next) => {
185246
// 2. 缓存处理,在身份验证之后进行
186247
function cacheHandler() {
187248
// 尝试匹配缓存配置
188-
const cacheConf = settings.getCaches().find(routeFilter(req));
249+
const cacheConf = getMatchedRule(settings.getCaches(), req);
189250
if (cacheConf) {
190251
logMsg += `命中缓存规则 {${cacheConf._id}} --> `;
191252

192-
if (req.headers['redis-cache-ignore']) {
193-
// ServerLog 支持绕过缓存,方便开发和测试
194-
logMsg += '不走缓存 (通过 ServerLog 绕过缓存) --> ';
195-
routeHandler();
196-
} else if (req.query[debugMode.debugParam] === 'true') {
253+
if (req.query[debugMode.debugParam] === 'true') {
197254
// 调试模式绕过缓存
198255
logMsg += '不走缓存 (调试模式绕过缓存) --> ';
199256
routeHandler();
@@ -288,7 +345,7 @@ app.use((req, res, next) => {
288345
}
289346

290347
// 尝试匹配普通路由规则
291-
const route = settings.getRoutes().find(routeFilter(req));
348+
const route = getMatchedRule(settings.getRoutes(), req);
292349

293350
// 找不到匹配的规则
294351
if (!route) {
@@ -395,13 +452,15 @@ app.use((req, res, next) => {
395452
}
396453

397454
// 1. 尝试匹配身份验证规则
398-
const permission = settings.getPermissions().find(routeFilter(req));
455+
const permission = getMatchedRule(settings.getPermissions(), req);
399456
if (permission) {
400457
logMsg += `命中身份验证规则 {${permission._id}} --> `;
401458

402459
// 找到了规则,继续判断是否在排除项中
403460
const excludes = permission.excludes;
404-
const exclude = excludes.find(routeFilter(req));
461+
462+
//TODO:
463+
const exclude = null;
405464

406465
// 无符合的排除项,说明必须走身份验证
407466
if (!exclude) {
@@ -485,5 +544,6 @@ if (config.ssl.enable) {
485544
server = http.createServer(app);
486545
}
487546
server.listen(app.get('port'), () => {
488-
logger.info('Noginx listening on port', server.address().port, 'with pid', process.pid);
547+
const port = server.address().port;
548+
logger.info(`Noginx listening on port ${port} with pid ${process.pid}, Admin URL: ${config.ssl.enable ? 'https' : 'http'}://localhost:${port}/noginx`);
489549
});

0 commit comments

Comments
 (0)