Authored by 郝肖肖

'limiter-限流'

... ... @@ -59,7 +59,7 @@ exports.submit = (req, res) => {
if (geetestRes) {
logger.info('geetest success');
let remoteIp = req.get('X-Forwarded-For') || req.ip;
let remoteIp = req.yoho.clientIp;
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
... ... @@ -67,7 +67,25 @@ exports.submit = (req, res) => {
remoteIp = arr[0];
}
let operations = [cache.delAsync(`${config.app}:limiter:${remoteIp}`)];
// pc:limiter:IP 和PC端共用
let operations = [cache.delAsync(`pc:limiter:${remoteIp}`)];
// 验证码之后一小时之内不再限制qps
if (req.session.apiLimitValidate) {
operations.push(cache.setAsync(
`${config.app}:limiter:api:ishuman:${remoteIp}`,
1,
config.LIMITER_IP_TIME
));
} else {
operations.push(cache.setAsync(
`${config.app}:limiter:ishuman:${remoteIp}`,
1,
config.LIMITER_IP_TIME
));
}
delete req.session.apiLimitValidate;
if (req.body.pid) {
let riskPid = decodeURIComponent(req.body.pid) + ':' + _.get(req.yoho, 'clientIp', '');
... ...
... ... @@ -160,6 +160,7 @@ module.exports = {
// 100s 最多访问200次
600: 200
},
LIMITER_IP_TIME: 3600, // 超出访问限制ip限制访问1小时
superCapture: '93c70db61fe276f93ce781ad17dc47cd',
from: from
};
... ...
... ... @@ -4,8 +4,10 @@
*/
const headerModel = require('../models/header');
const logger = global.yoho.logger;
const cache = global.yoho.cache.master;
const helpers = global.yoho.helpers;
const sender = global.yoho.apmSender;
const config = global.yoho.config;
const hostname = require('os').hostname();
const routeEncode = require('./route-encode');
const _ = require('lodash');
... ... @@ -20,6 +22,51 @@ const forceNoCache = (res) => {
}
};
const _err510 = (req, res, code, err) => {
res.status(code);
if (req.xhr) {
return res.json({
code: err.code,
message: '服务器繁忙请稍后重试!'
});
}
return res.render('error/510', {
err: err,
module: 'common',
page: 'error',
title: '服务器繁忙 | Yoho!Buy有货 | 潮流购物逛不停',
pageHeader: headerModel.setNav({
navTitle: '服务器繁忙请稍后重试!'
}),
pageFooter: true,
isErr: true
});
};
const _err500 = (req, res, code, err) => {
res.status(code);
if (req.xhr) {
return res.json({
code: err.code,
message: '服务器错误!'
});
}
return res.render('error/500', {
err: err,
module: 'common',
page: 'error',
title: '服务器错误 | Yoho!Buy有货 | 潮流购物逛不停',
pageHeader: headerModel.setNav({
navTitle: '服务器错误!'
}),
pageFooter: true,
isErr: true
});
};
exports.notFound = () => {
return (req, res) => {
... ... @@ -51,11 +98,12 @@ exports.notFound = () => {
* @return {[type]}
*/
exports.serverError = () => {
return (err, req, res, next) => {
forceNoCache(res);
return async (err, req, res, next) => {
const uid = req.user ? req.user.uid : 0;
const udid = _.get(req, 'cookies.udid', 'yoho');
forceNoCache(res);
err.code = err.code || err.statusCode || 500;
if (req.isApmReport && err.code !== 401) {
... ... @@ -63,7 +111,7 @@ exports.serverError = () => {
sender.addMessage({
measurement: 'error-report',
tags: {
app: global.yoho.config.appName, // 应用名称
app: config.appName, // 应用名称
hostname,
type: 'server',
route: `[${req.method}]${_.get(req, 'route.path', '')}`, // 请求路由
... ... @@ -106,33 +154,45 @@ exports.serverError = () => {
refer: req.originalUrl
}));
}
}
} else if (err.code === 9999991 || err.code === 9999992) {
let remoteIp = req.yoho.clientIp;
logger.error(`error at path: ${req.url}`);
logger.error(err);
const isHuman = await cache.getAsync(`${config.app}:limiter:api:ishuman:${remoteIp}`);
if (!res.headersSent) {
res.status(err.code);
if (!isHuman) {
if (remoteIp.indexOf(',') > 0) {
let arr = remoteIp.split(',');
if (req.xhr) {
return res.json({
code: err.code,
message: '服务器错误!'
remoteIp = arr[0];
}
cache.setAsync(`${config.app}:limiter:${remoteIp}`, 1, config.LIMITER_IP_TIME);
let limitAPI = helpers.urlFormat('/3party/check', {refer: req.get('Referer') || ''});
let limitPage = helpers.urlFormat('/3party/check', {
refer: req.protocol + '://' + req.get('host') + req.originalUrl
});
req.session.apiLimitValidate = true;
if (req.xhr) {
return res.status(510).json({
code: err.code,
data: {refer: limitAPI}
});
}
return res.redirect(limitPage);
}
return res.render('error/500', {
err: err,
module: 'common',
page: 'error',
title: '服务器错误 | Yoho!Buy有货 | 潮流购物逛不停',
pageHeader: headerModel.setNav({
navTitle: '服务器错误!'
}),
pageFooter: true,
isErr: true
});
return _err510(req, res, 510, err);
}
logger.error(`error at path: ${req.url}`);
logger.error(err);
if (!res.headersSent) {
return _err500(req, res, err.code, err);
}
next(err);
return next(err);
};
};
... ...
... ... @@ -10,9 +10,6 @@ const cache = global.yoho.cache.master;
const config = global.yoho.config;
const _ = require('lodash');
// 超出访问限制ip限制访问1小时
const limiterIpTime = 3600;
// 页面访问限制
const MAX_TIMES = config.REQUEST_LIMIT;
... ... @@ -51,7 +48,7 @@ module.exports = (limiter, policy) => {
logger.warn(`pc:limiter:${limiter.remoteIp}`);
// ip限制1小时
operation.push(cache.setAsync(`pc:limiter:${limiter.remoteIp}`, 1, limiterIpTime));
operation.push(cache.setAsync(`pc:limiter:${limiter.remoteIp}`, 1, config.LIMITER_IP_TIME));
return Promise.resolve(policy);
} else {
operation.push(cache.incrAsync(cacheKey, 1));
... ...
<div class="err-page yoho-page">
<div class="err-bg"></div>
</div>
... ...