qps-limit.js 2.05 KB
/**
 * 限制页面访问次数,如超过限制次数,返回相应策略(目前是ip加入黑名单,跳转图形验证码页面,解除限制)
 * 当前规则只针对未登录用户
 */

'use strict';

const logger = global.yoho.logger;
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;

module.exports = (limiter, policy) => {

    // 存储规则的cache keys
    let ruleKeys = {};
    let getOp = {};

    _.forEach(MAX_TIMES, (val, key) => {
        ruleKeys[key] = `${config.app}:limiter:${key}:max:${limiter.remoteIp}`;
        getOp[key] = cache.getAsync(ruleKeys[key]);
    });

    getOp.human = cache.getAsync(`${config.app}:limiter:ishuman:${limiter.remoteIp}`);

    return Promise.props(getOp).then((results) => {

        logger.debug(MAX_TIMES);
        logger.debug(_.values(ruleKeys));
        logger.debug(results);

        if (results.human) { // 经过验证码之后1小时有效期内不再验证qps
            return Promise.resolve(true);
        }

        // 遍历限制规则,若满足返回相应处理策略, 否则页面访问次数加1
        let operation = [];

        _.forEach(MAX_TIMES, (val, key) => {
            let cacheKey = ruleKeys[key];

            if (!results[key]) {
                operation.push(cache.setAsync(cacheKey, 1, +key));
            } else if (+results[key] > +val) {
                logger.warn(`${config.app}:limiter:${limiter.remoteIp}`);

                // ip限制1小时
                operation.push(cache.setAsync(`${config.app}:limiter:${limiter.remoteIp}`, 1, limiterIpTime));
                return Promise.resolve(policy);
            } else {
                operation.push(cache.incrAsync(cacheKey, 1));
            }
        });

        Promise.all(operation);

        // 不满足任何限制规则,继续访问
        return Promise.resolve(true);
    }).catch(err=>{
        logger.error(err);
    });
};