Merge branch 'feature/req-limiter'
Showing
6 changed files
with
77 additions
and
4 deletions
@@ -51,6 +51,9 @@ if (config.zookeeperServer) { | @@ -51,6 +51,9 @@ if (config.zookeeperServer) { | ||
51 | require('yoho-zookeeper')(config.zookeeperServer, 'pc', app.locals.pc = {}, global.yoho.cache); | 51 | require('yoho-zookeeper')(config.zookeeperServer, 'pc', app.locals.pc = {}, global.yoho.cache); |
52 | } | 52 | } |
53 | 53 | ||
54 | +// 请求限制中间件 | ||
55 | +app.use(require('./doraemon/middleware/limiter')); | ||
56 | + | ||
54 | app.set('subdomain offset', 2); | 57 | app.set('subdomain offset', 2); |
55 | app.use(global.yoho.hbs({ | 58 | app.use(global.yoho.hbs({ |
56 | extname: '.hbs', | 59 | extname: '.hbs', |
@@ -15,7 +15,7 @@ const specialController = require(`${cRoot}/special`); | @@ -15,7 +15,7 @@ const specialController = require(`${cRoot}/special`); | ||
15 | const coupon = require(`${cRoot}/coupon`); | 15 | const coupon = require(`${cRoot}/coupon`); |
16 | 16 | ||
17 | // 专题活动 | 17 | // 专题活动 |
18 | -router.get(/^\/special\/(\d+)_(.*)\.html$/, specialController.special); | 18 | +router.get(/^\/special\/(\d+)_/, specialController.special); |
19 | 19 | ||
20 | // 领券中心 | 20 | // 领券中心 |
21 | router.get('/coupon/index', coupon.index); | 21 | router.get('/coupon/index', coupon.index); |
@@ -9,7 +9,7 @@ | @@ -9,7 +9,7 @@ | ||
9 | const router = require('express').Router(); // eslint-disable-line | 9 | const router = require('express').Router(); // eslint-disable-line |
10 | const cRoot = './controllers'; | 10 | const cRoot = './controllers'; |
11 | const auth = require(`${global.middleware}/auth`); | 11 | const auth = require(`${global.middleware}/auth`); |
12 | -// const filter = require(`${global.middleware}/filter-qs`); // 参数过滤 | 12 | +const gbk2utf = require(`${global.middleware}/gbk2utf`); |
13 | 13 | ||
14 | // 商品详情controller | 14 | // 商品详情controller |
15 | const detail = require(`${cRoot}/detail`); | 15 | const detail = require(`${cRoot}/detail`); |
@@ -83,13 +83,13 @@ router.post('/detail/notify/add', auth, notify.add); // 增 | @@ -83,13 +83,13 @@ router.post('/detail/notify/add', auth, notify.add); // 增 | ||
83 | router.post('/detail/notify/cancel', auth, notify.cancel); // 删除到货通知 | 83 | router.post('/detail/notify/cancel', auth, notify.cancel); // 删除到货通知 |
84 | 84 | ||
85 | // 搜索 | 85 | // 搜索 |
86 | -router.get('/search/index', search.index); | 86 | +router.get('/search/index', gbk2utf, search.index); |
87 | router.get('/search/filter/brands', search.serachFilterBrands); | 87 | router.get('/search/filter/brands', search.serachFilterBrands); |
88 | router.get('/search/suggest', search.suggest); // 搜索提示 | 88 | router.get('/search/suggest', search.suggest); // 搜索提示 |
89 | router.get('/api/suggest', search.suggest4Old); | 89 | router.get('/api/suggest', search.suggest4Old); |
90 | 90 | ||
91 | // 商品分类列表页 | 91 | // 商品分类列表页 |
92 | -router.get('/list/index', list.index); | 92 | +router.get('/list/index', gbk2utf, list.index); |
93 | 93 | ||
94 | // 新品到着 | 94 | // 新品到着 |
95 | router.get('/list/new', list.new); | 95 | router.get('/list/new', list.new); |
doraemon/middleware/gbk2utf.js
0 → 100644
1 | +'use strict'; | ||
2 | + | ||
3 | +const urlEncode = require('urlencode'); | ||
4 | +const _ = require('lodash'); | ||
5 | +const helpers = global.yoho.helpers; | ||
6 | +const allowSubDomain = ['list', 'search']; | ||
7 | + | ||
8 | + | ||
9 | +module.exports = (req, res, next) => { | ||
10 | + let query = req.query.query; | ||
11 | + let subDomain = req.subdomains[0]; | ||
12 | + | ||
13 | + if (query && _.includes(allowSubDomain, subDomain)) { | ||
14 | + try { | ||
15 | + decodeURIComponent(query); | ||
16 | + return next(); | ||
17 | + } catch (e) { | ||
18 | + try { | ||
19 | + query = urlEncode.decode(query, 'gb2312'); | ||
20 | + req.query.query = query; | ||
21 | + return res.status(301).redirect(helpers.urlFormat('', req.query, subDomain)); | ||
22 | + } catch (e1) { | ||
23 | + return res.redirect(helpers.urlFormat('', null, subDomain)); | ||
24 | + } | ||
25 | + } | ||
26 | + } | ||
27 | + | ||
28 | + return next(); | ||
29 | +}; |
doraemon/middleware/limiter.js
0 → 100644
1 | + | ||
2 | +'use strict'; | ||
3 | + | ||
4 | +const cache = global.yoho.cache.master; | ||
5 | +const _ = require('lodash'); | ||
6 | +const logger = global.yoho.logger; | ||
7 | + | ||
8 | +module.exports = (req, res, next) => { | ||
9 | + let remoteIp = req.get('X-Forwarded-For') || ''; | ||
10 | + | ||
11 | + if (remoteIp.indexOf(',') > 0) { | ||
12 | + let arr = remoteIp.split(','); | ||
13 | + remoteIp = arr[0]; | ||
14 | + } | ||
15 | + | ||
16 | + if (remoteIp && !_.get(req.app.locals, 'pc.sys.noLimiter')) { // 判断获取remoteIp成功,并且开关未关闭 | ||
17 | + let key = `pc:limiter:${remoteIp}`; | ||
18 | + | ||
19 | + logger.debug(`request limiter key=${key}`); | ||
20 | + | ||
21 | + cache.getAsync(key).then(result => { | ||
22 | + if (result && _.isNumber(result)) { | ||
23 | + if (result > 30) { // 判断 qps | ||
24 | + res.status(403).end(); | ||
25 | + } else { | ||
26 | + cache.incrAsync(key, 1); // qps + 1 | ||
27 | + next(); | ||
28 | + } | ||
29 | + } else { | ||
30 | + cache.setAsync(key, 1, 1); // 设置key,1s失效 | ||
31 | + next(); | ||
32 | + } | ||
33 | + }).catch(e => { | ||
34 | + logger.error(`request limiter get key[${key}] from cache error.`, e); | ||
35 | + next(); | ||
36 | + }); | ||
37 | + } else { | ||
38 | + next(); | ||
39 | + } | ||
40 | +}; |
@@ -59,6 +59,7 @@ | @@ -59,6 +59,7 @@ | ||
59 | "request-ip": "^1.2.2", | 59 | "request-ip": "^1.2.2", |
60 | "request-promise": "^3.0.0", | 60 | "request-promise": "^3.0.0", |
61 | "serve-favicon": "^2.3.0", | 61 | "serve-favicon": "^2.3.0", |
62 | + "urlencode": "^1.1.0", | ||
62 | "uuid": "^2.0.2", | 63 | "uuid": "^2.0.2", |
63 | "yoho-express-session": "^2.0.0", | 64 | "yoho-express-session": "^2.0.0", |
64 | "yoho-node-lib": "0.2.5", | 65 | "yoho-node-lib": "0.2.5", |
-
Please register or login to post a comment