Java 限制重复请求:实现策略与代码示例

在Web开发中,限制用户在短时间内的重复请求是一种常见的需求,以避免恶意攻击或减轻服务器压力。本文将介绍Java中实现限制重复请求的几种策略,并提供相应的代码示例。

流程图

首先,我们通过一个流程图来概述限制重复请求的基本流程:

是首次请求 非首次请求 时间差小于阈值 时间差大于阈值 开始 检查请求 记录请求时间 计算时间差 拒绝请求 更新请求时间 处理请求 结束

策略概览

  1. 基于时间戳的简单限制:记录每个用户的最后请求时间,如果在短时间内再次请求,则拒绝。
  2. 使用缓存实现限制:利用缓存(如Redis)存储用户的请求次数和时间戳,实现更高效的限制。
  3. 滑动窗口算法:记录用户在一定时间窗口内的请求次数,超过阈值则拒绝。

代码示例

1. 基于时间戳的简单限制
import java.util.HashMap;
import java.util.Map;

public class SimpleRequestLimiter {
    private static final Map<String, Long> lastRequestTime = new HashMap<>();
    private static final long TIME_LIMIT = 1000; // 1秒内只允许一次请求

    public static boolean isAllowed(String userId) {
        Long lastTime = lastRequestTime.get(userId);
        long currentTime = System.currentTimeMillis();

        if (lastTime != null && (currentTime - lastTime < TIME_LIMIT)) {
            return false; // 请求过于频繁
        }

        lastRequestTime.put(userId, currentTime);
        return true;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
2. 使用Redis实现限制
import redis.clients.jedis.Jedis;

public class RedisRequestLimiter {
    private static final Jedis jedis = new Jedis("localhost", 6379);

    public static boolean isAllowed(String userId) {
        String key = "request:" + userId;
        long currentTime = System.currentTimeMillis();

        Long lastRequestTime = jedis.getSet(key, currentTime + "");
        if (lastRequestTime != null && (currentTime - Long.parseLong(lastRequestTime + "") < 1000)) {
            return false; // 请求过于频繁
        }

        jedis.expire(key, 10); // 设置过期时间为10秒
        return true;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
3. 滑动窗口算法
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

public class SlidingWindowLimiter {
    private static final ConcurrentHashMap<String, AtomicInteger> requestCount = new ConcurrentHashMap<>();
    private static final int MAX_REQUESTS = 5; // 5次请求

    public static boolean isAllowed(String userId) {
        AtomicInteger count = requestCount.computeIfAbsent(userId, k -> new AtomicInteger(0));
        if (count.incrementAndGet() > MAX_REQUESTS) {
            count.set(0); // 超过阈值,重置计数器
            return false;
        }
        return true;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.

总结

通过上述代码示例,我们可以看到Java中实现限制重复请求的几种策略。每种策略都有其适用场景和优缺点。基于时间戳的简单限制易于实现,但可能不够精确;使用Redis可以提高性能和扩展性;滑动窗口算法则可以更精确地控制请求频率。

开发者应根据实际需求和资源情况,选择最合适的策略来实现限制重复请求的功能。同时,也要注意合理设置阈值,避免影响正常用户的使用体验。