Authored by 周少峰

Merge branch 'feature/req-limiter'

... ... @@ -51,6 +51,9 @@ if (config.zookeeperServer) {
require('yoho-zookeeper')(config.zookeeperServer, 'pc', app.locals.pc = {}, global.yoho.cache);
}
// 请求限制中间件
app.use(require('./doraemon/middleware/limiter'));
app.set('subdomain offset', 2);
app.use(global.yoho.hbs({
extname: '.hbs',
... ...
... ... @@ -15,7 +15,7 @@ const specialController = require(`${cRoot}/special`);
const coupon = require(`${cRoot}/coupon`);
// 专题活动
router.get(/^\/special\/(\d+)_(.*)\.html$/, specialController.special);
router.get(/^\/special\/(\d+)_/, specialController.special);
// 领券中心
router.get('/coupon/index', coupon.index);
... ...
... ... @@ -9,7 +9,7 @@
const router = require('express').Router(); // eslint-disable-line
const cRoot = './controllers';
const auth = require(`${global.middleware}/auth`);
// const filter = require(`${global.middleware}/filter-qs`); // 参数过滤
const gbk2utf = require(`${global.middleware}/gbk2utf`);
// 商品详情controller
const detail = require(`${cRoot}/detail`);
... ... @@ -83,13 +83,13 @@ router.post('/detail/notify/add', auth, notify.add); // 增
router.post('/detail/notify/cancel', auth, notify.cancel); // 删除到货通知
// 搜索
router.get('/search/index', search.index);
router.get('/search/index', gbk2utf, search.index);
router.get('/search/filter/brands', search.serachFilterBrands);
router.get('/search/suggest', search.suggest); // 搜索提示
router.get('/api/suggest', search.suggest4Old);
// 商品分类列表页
router.get('/list/index', list.index);
router.get('/list/index', gbk2utf, list.index);
// 新品到着
router.get('/list/new', list.new);
... ...
'use strict';
const urlEncode = require('urlencode');
const _ = require('lodash');
const helpers = global.yoho.helpers;
const allowSubDomain = ['list', 'search'];
module.exports = (req, res, next) => {
let query = req.query.query;
let subDomain = req.subdomains[0];
if (query && _.includes(allowSubDomain, subDomain)) {
try {
decodeURIComponent(query);
return next();
} catch (e) {
try {
query = urlEncode.decode(query, 'gb2312');
req.query.query = query;
return res.status(301).redirect(helpers.urlFormat('', req.query, subDomain));
} catch (e1) {
return res.redirect(helpers.urlFormat('', null, subDomain));
}
}
}
return next();
};
... ...
'use strict';
const cache = global.yoho.cache.master;
const _ = require('lodash');
const logger = global.yoho.logger;
module.exports = (req, res, next) => {
let remoteIp = req.get('X-Forwarded-For') || '';
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
remoteIp = arr[0];
}
if (remoteIp && !_.get(req.app.locals, 'pc.sys.noLimiter')) { // 判断获取remoteIp成功,并且开关未关闭
let key = `pc:limiter:${remoteIp}`;
logger.debug(`request limiter key=${key}`);
cache.getAsync(key).then(result => {
if (result && _.isNumber(result)) {
if (result > 30) { // 判断 qps
res.status(403).end();
} else {
cache.incrAsync(key, 1); // qps + 1
next();
}
} else {
cache.setAsync(key, 1, 1); // 设置key,1s失效
next();
}
}).catch(e => {
logger.error(`request limiter get key[${key}] from cache error.`, e);
next();
});
} else {
next();
}
};
... ...
... ... @@ -59,6 +59,7 @@
"request-ip": "^1.2.2",
"request-promise": "^3.0.0",
"serve-favicon": "^2.3.0",
"urlencode": "^1.1.0",
"uuid": "^2.0.2",
"yoho-express-session": "^2.0.0",
"yoho-node-lib": "0.2.5",
... ...