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

Spring Boot 3.4.1请求大小过滤器触发后连接拒绝问题

问题描述

环境:Spring Boot 3.4.1、Java 21

我编写了一个RequestSizeFilter过滤器,用于检查请求大小是否超过可配置的最大值,超出则返回413状态码。过滤器代码如下:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class RequestSizeFilter implements Filter {

    @Value("${fam.max_request_size:10485760}")
    private int maxContentBytes;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException {
        try {
            if (request.getContentLength() > maxContentBytes) {
                throw new RuntimeException();
            } else {
                chain.doFilter(request, response);
            }
        } catch (Exception e) {
            log.error("Detected overlarge request of %s bytes. Rejecting.".formatted(request.getContentLength()));
            HttpServletResponse httpResponse = (HttpServletResponse) response;
            httpResponse.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
            httpResponse.getWriter().println("Request exceeds maximum size of %s bytes".formatted(maxContentBytes));
        }

    }
}

运行端到端集成测试时,过滤器能正确识别超大请求并返回对应状态和错误信息,但触发拦截后,后续所有访问该端点的测试均失败,报错如下:

org.springframework.web.reactive.function.client.WebClientRequestException: Connection refused: localhost/[0:0:0:0:0:0:0:1]:8080
        at app//org.springframework.web.reactive.function.client.ExchangeFunctions$DefaultExchangeFunction.lambda$wrapException$9(ExchangeFunctions.java:137)

        Caused by:
        io.netty.channel.AbstractChannel$AnnotatedConnectException: Connection refused: localhost/[0:0:0:0:0:0:0:1]:8080

            Caused by:
            java.net.ConnectException: Connection refused
                at java.base/sun.nio.ch.Net.pollConnect(Native Method)
                at java.base/sun.nio.ch.Net.pollConnectNow(Net.java:682)
                at java.base/sun.nio.ch.SocketChannelImpl.finishConnect(SocketChannelImpl.java:973)
                at io.netty.channel.socket.nio.NioSocketChannel.doFinishConnect(NioSocketChannel.java:336)
                at io.netty.channel.nio.AbstractNioChannel$AbstractNioUnsafe.finishConnect(AbstractNioChannel.java:339)
                at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:776)
                at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:724)
                at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:650)
                at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
                at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
                at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
                at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
                at java.base/java.lang.Thread.run(Thread.java:1583)

测试使用基于Spring WebTestClient自定义的客户端,仅配置了基础URL和默认授权头。禁用触发过滤器的测试后,其他测试均可通过;且测试顺序不固定时,同一测试在触发过滤器前运行通过,触发后则失败。推测过滤器导致服务器状态不稳定,想问需要执行什么操作让服务恢复接受连接的状态?


问题分析与修复方案

问题根源

过滤器存在两个核心问题,导致服务器连接异常:

  1. 未处理请求体读取:请求超限时直接返回响应,但未读取并丢弃请求体。Servlet容器会认为连接仍在处理请求,导致后续请求无法复用连接,甚至引发连接资源泄漏。
  2. 异常处理不规范:直接抛出RuntimeException干扰容器正常流程,且未确保响应被正确提交,进一步加剧连接状态异常。

修复步骤

无需重置服务,修改过滤器代码即可解决问题:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
@Slf4j
public class RequestSizeFilter implements Filter {

    @Value("${fam.max_request_size:10485760}")
    private int maxContentBytes;

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;

        int contentLength = httpRequest.getContentLength();
        if (contentLength > maxContentBytes) {
            // 读取并丢弃请求体,释放连接资源
            try (InputStream inputStream = httpRequest.getInputStream()) {
                byte[] buffer = new byte[1024];
                while (inputStream.read(buffer) != -1) {
                    // 丢弃读取内容
                }
            } catch (IOException e) {
                log.warn("Failed to read oversized request body", e);
            }

            // 返回413响应并确保提交
            log.error("Detected overlarge request of {} bytes. Rejecting.", contentLength);
            httpResponse.setStatus(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE);
            httpResponse.setContentType("text/plain");
            httpResponse.getWriter().println("Request exceeds maximum size of {} bytes".formatted(maxContentBytes));
            httpResponse.flushBuffer();
            return;
        }

        // 请求大小合规,继续执行过滤器链
        chain.doFilter(request, response);
    }
}

关键改进点

  • 读取并丢弃请求体:确保Servlet容器认为请求已处理完成,避免连接资源被占用。
  • 移除不必要的异常抛出:直接处理超限逻辑,不干扰容器正常流程。
  • 强制提交响应:调用flushBuffer()确保响应完全发送,释放连接供后续请求使用。

额外测试建议

若修改后仍有问题,可检查:

  • 测试类是否添加@DirtiesContext注解:如果测试会改变应用状态,该注解可在测试后重置Spring上下文(优先修复过滤器代码,此为兜底方案)。
  • WebTestClient配置:确保客户端每次请求后正确释放连接。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 21:35:10