Authored by 姜枫

add req limiter blacklist

... ... @@ -5,6 +5,23 @@ const cache = global.yoho.cache.master;
const _ = require('lodash');
const logger = global.yoho.logger;
let ONE_DAY = 60 * 60 * 24;
let pages = {
'/product/\\/pro_([\\d]+)_([\\d]+)\\/(.*)/': 5,
'/product/list/index': 5
};
function urlJoin(a, b) {
if (_.endsWith(a, '/') && _.startsWith(b, '/')) {
return a + b.substring(1, b.length);
} else if (!_.endsWith(a, '/') && !_.startsWith(b, '/')) {
return a + '/' + b;
} else {
return a + b;
}
}
module.exports = (req, res, next) => {
let remoteIp = req.get('X-Forwarded-For') || '';
... ... @@ -13,21 +30,39 @@ module.exports = (req, res, next) => {
remoteIp = arr[0];
}
if (remoteIp && !_.get(req.app.locals, 'pc.sys.noLimiter')) { // 判断获取remoteIp成功,并且开关未关闭
if (remoteIp && !_.get(req.app.locals, 'pc.sys.noLimiter')) { // 判断获取remoteIp成功,并且开关未关闭
let key = `pc:limiter:${remoteIp}`;
logger.debug(`request limiter key=${key}`);
res.on('render', function() {
let route = req.route ? req.route.path : '';
let appPath = req.app.mountpath;
if (_.isArray(route) && route.length > 0) {
route = route[0];
}
let pageKey = urlJoin(appPath, route.toString()); // route may be a regexp
let pageIncr = pages[pageKey] || 0;
if (pageIncr > 0) {
cache.incrAsync(key, pageIncr);
}
});
cache.getAsync(key).then(result => {
if (result && _.isNumber(result)) {
if (result > 30) { // 判断 qps
if (result > 1800) { // 判断 qps
cache.touch(key, ONE_DAY);
console.log('req limit', key);
res.status(403).end();
} else {
cache.incrAsync(key, 1); // qps + 1
next();
}
} else {
cache.setAsync(key, 1, 1); // 设置key,1s失效
cache.setAsync(key, 1, 60); // 设置key,1s失效
next();
}
}).catch(e => {
... ... @@ -37,4 +72,6 @@ module.exports = (req, res, next) => {
} else {
next();
}
};
... ...