服务器怎么设置限制n次?

在服务器上设置访问限制,主要有以下几种常见方式:

1. Nginx 限流配置

基于 IP 限制访问频率

http {
    # 定义限流区域
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    
    server {
        location /api/ {
            # 应用限流,burst=5 允许突发5个请求
            limit_req zone=api burst=5 nodelay;
            proxy_pass http://backend;
        }
    }
}

限制并发连接数

http {
    limit_conn_zone $binary_remote_addr zone=conn:10m;
    
    server {
        location /download/ {
            limit_conn conn 5;  # 每个IP最多5个并发连接
        }
    }
}

2. Apache 限流配置

使用 mod_security

<IfModule mod_security.c>
    SecRuleEngine On
    # 限制每分钟最多60次请求
    SecRule REQUEST_URI "@streq /api" "phase:1,deny,status:429,\
        setvar:ip.requests=+1,expirevar:ip.requests=60"
</IfModule>

3. 应用层限流(以 Node.js 为例)

使用 express-rate-limit

const rateLimit = require('express-rate-limit');
const limiter = rateLimit({
    windowMs: 15 * 60 * 1000, // 15分钟
    max: 100, // 限制每个IP在15分钟内最多100次请求
    message: '请求过于频繁,请稍后再试'
});
app.use(limiter);

自定义限流中间件

const rateLimitMap = new Map();
function rateLimitMiddleware(req, res, next) {
    const ip = req.ip;
    const now = Date.now();
    const windowMs = 60000; // 1分钟
    const maxRequests = 60; // 最多60次请求
    
    if (!rateLimitMap.has(ip)) {
        rateLimitMap.set(ip, { count: 1, startTime: now });
    } else {
        const data = rateLimitMap.get(ip);
        
        if (now - data.startTime > windowMs) {
            // 重置时间窗口
            data.count = 1;
            data.startTime = now;
        } else {
            data.count++;
            
            if (data.count > maxRequests) {
                return res.status(429).json({
                    error: '请求过于频繁,请稍后再试'
                });
            }
        }
    }
    
    next();
}
app.use(rateLimitMiddleware);

4. 使用 Redis 实现分布式限流

const redis = require('redis');
const client = redis.createClient();
async function redisRateLimit(ip, maxRequests, windowMs) {
    const key =rate_limit:${ip};
    
    const current = await client.incr(key);
    if (current === 1) {
        await client.expire(key, windowMs / 1000);
    }
    
    if (current > maxRequests) {
        return false; // 超过限制
    }
    
    return true;
}
app.use(async (req, res, next) => {
    const allowed = await redisRateLimit(req.ip, 100, 60000);
    if (!allowed) {
        return res.status(429).json({ error: '请求过于频繁' });
    }
    next();
});

5. iptables 限制连接数

限制每个IP最多10个并发连接
iptables -A INPUT -p tcp --syn --dport 80 -m connlimit --connlimit-above 10 -j REJECT
限制每分钟最多30个新连接
iptables -A INPUT -p tcp --dport 80 -m limit --limit 30/minute -j ACCEPT
iptables -A INPUT -p tcp --dport 80 -j DROP

6. 使用 fail2ban 自动封禁

/etc/fail2ban/jail.local
[nginx-limit-req]
enabled = true
filter = nginx-limit-req
action = iptables-multiport[name=nginx-limit-req, port="http,https"]
logpath = /var/log/nginx/error.log
maxretry = 5
findtime = 600
bantime = 3600

最佳实践建议

1、分层限流:在多个层面设置限流(网络层、Web服务器层、应用层)

2、差异化限流:对不同的API端点设置不同的限制

3、合理的限制值:根据业务需求设置合理的限制值

4、返回适当的状态码:使用 429 Too Many Requests

5、添加重试头部:在响应中包含Retry-After 头部

选择哪种方式取决于你的具体需求、服务器架构和技术栈。

文章摘自:https://idc.huochengrm.cn/fwq/17529.html

评论