You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中使用Bucket4j实现限流时自定义HTTP响应体

自定义Bucket4j限流动态响应体的实现方案

刚好我之前也处理过类似的需求,配置文件里的静态响应确实没法满足动态字段(比如时间戳)的需求,给你两种实用的方案来实现自定义动态响应体:

方案一:全局异常处理器捕获限流异常

Bucket4j触发限流时会抛出RateLimitExceededException异常,我们可以通过Spring的全局异常处理器来捕获这个异常,然后返回包含动态字段的响应体。这种方式简单直观,适合大多数场景。

实现代码

import io.github.bucket4j.RateLimitExceededException;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@RestControllerAdvice
public class RateLimitExceptionHandler {

    @ExceptionHandler(RateLimitExceededException.class)
    public ResponseEntity<Map<String, Object>> handleRateLimitExceeded(RateLimitExceededException e) {
        Map<String, Object> response = new HashMap<>();
        response.put("status", HttpStatus.TOO_MANY_REQUESTS.value());
        response.put("error", "Too Many Requests");
        response.put("message", "API rate limit exceeded");
        // 添加动态时间戳
        response.put("timestamp", Instant.now().toString());
        // 可选:从异常中获取重试等待时间(转成秒)
        response.put("retryAfter", e.getRetryAfterNanos() / 1000_000_000);

        return new ResponseEntity<>(response, HttpStatus.TOO_MANY_REQUESTS);
    }
}

注意事项

  • 写完这个处理器后,记得删除application.properties里的bucket4j.filters[0].http-response-body配置,避免冲突。
  • 如果你的Bucket4j版本较低,异常类可能是BucketExecutionException,可以调整捕获的异常类型。

方案二:实现Bucket4j的ErrorResponseHandler接口

这种方式更贴合Bucket4j的扩展机制,通过实现它提供的ErrorResponseHandler接口,直接接管限流时的响应处理逻辑,能获取到更多请求相关的上下文信息。

实现代码

import io.github.bucket4j.spring.boot.error.ErrorResponseHandler;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
import com.fasterxml.jackson.databind.ObjectMapper;

import java.io.IOException;
import java.time.Instant;
import java.util.HashMap;
import java.util.Map;

@Component
public class CustomRateLimitErrorResponseHandler implements ErrorResponseHandler {

    private final ObjectMapper objectMapper;

    // 注入Spring默认的ObjectMapper来序列化响应体
    public CustomRateLimitErrorResponseHandler(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, String message) throws IOException {
        response.setStatus(HttpServletResponse.SC_TOO_MANY_REQUESTS);
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);

        Map<String, Object> responseBody = new HashMap<>();
        responseBody.put("status", HttpServletResponse.SC_TOO_MANY_REQUESTS);
        responseBody.put("error", "Too Many Requests");
        responseBody.put("message", message != null ? message : "API rate limit exceeded");
        // 添加动态时间戳
        responseBody.put("timestamp", Instant.now().toString());
        // 可选:添加当前请求的路径
        responseBody.put("path", request.getRequestURI());

        // 将响应体写入输出流
        objectMapper.writeValue(response.getOutputStream(), responseBody);
    }
}

注意事项

  • 确保你的bucket4j-spring-boot-starter版本支持这个接口,不同版本的包路径可能略有差异(比如旧版可能在io.github.bucket4j.spring.web.servlet.error下),如果找不到接口可以检查版本或调整导入路径。
  • 这个Bean会被Bucket4j自动识别并使用,不需要额外配置。

两种方案都能实现动态自定义响应体,你可以根据自己的需求选择:如果只是简单加动态字段,方案一足够;如果需要更多请求上下文的信息,方案二更合适。

内容的提问来源于stack exchange,提问作者kkorat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 23:42:37