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

无HTTP请求体时@ControllerAdvice不触发handleEmptyBody的问题咨询

解决思路与问题解析

首先明确几个关键问题,再给出针对性的解决方案:

关于handleEmptyBody()的调用时机

Spring 只会在满足以下两个条件时调用handleEmptyBody():

  1. 你的supports()方法返回true;
  2. 控制器方法带有@RequestBody注解,但请求体为空(包括Content-Length为0、请求体是空白字符串,或者分块传输但无实际内容的情况)。

如果请求本身没有请求体(比如GET请求)且控制器方法没有@RequestBody参数,那么整个RequestBodyAdvice的方法都不会被触发,自然也不会走到handleEmptyBody()。

实现「仅在有请求体时触发Advice」的方案

你的需求是让这个@ControllerAdvice在任何无请求体的场景下完全被忽略(包括有@RequestBody但空体的情况),核心是在supports()方法中添加判断逻辑,仅当请求存在非空请求体时返回true,否则返回false。

具体步骤与代码修改

  1. 首先过滤非@RequestBody参数:因为RequestBodyAdvice本来就是为@RequestBody参数设计的,先明确只对这类参数生效;
  2. 判断请求是否带有非空请求体:通过HttpServletRequest获取请求信息,结合Content-Length、请求方法或缓存请求流来判断。

修改后的supports()方法示例:

import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.util.StringUtils;

// 其余导入保持不变

@Override
public boolean supports(
        MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType
) {
    // 第一步:仅对带有@RequestBody注解的参数生效
    if (!methodParameter.hasParameterAnnotation(RequestBody.class)) {
        LOGGER.info("当前方法无@RequestBody参数,忽略Advice");
        return false;
    }

    // 第二步:获取当前请求对象
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    if (attributes == null) {
        LOGGER.info("无法获取请求上下文,忽略Advice");
        return false;
    }
    HttpServletRequest request = attributes.getRequest();

    // 判断是否存在非空请求体
    boolean hasNonEmptyBody = false;
    // 先检查Content-Length(适用于非分块传输的场景)
    if (request.getContentLengthLong() > 0) {
        hasNonEmptyBody = true;
    } else {
        // 处理分块传输(Transfer-Encoding: chunked)的情况,缓存请求流并检查内容
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        byte[] bodyBytes = wrappedRequest.getContentAsByteArray();
        hasNonEmptyBody = bodyBytes.length > 0 && !StringUtils.isBlank(new String(bodyBytes, StandardCharsets.UTF_8).trim());
    }

    if (hasNonEmptyBody) {
        LOGGER.info("请求带有非空请求体,触发Advice");
        return true;
    } else {
        LOGGER.info("请求无有效请求体,忽略Advice");
        return false;
    }
}

关键细节说明

  • 对于GET这类通常不带请求体的方法,即使控制器方法误加了@RequestBody,上面的逻辑也会因为检测不到非空请求体而返回false,避免Advice被触发;
  • 使用ContentCachingRequestWrapper是为了安全地读取请求流内容(不会消耗流,后续HttpMessageConverter仍能正常读取);
  • 额外判断字符串是否为空白,是为了排除请求体全是空格、换行这类无意义内容的情况。

最终效果

修改后,只有当请求带有非空的请求体,且控制器方法参数带有@RequestBody时,你的RequestBodyAdvice的beforeBodyRead()、afterBodyRead()才会被触发;无请求体或请求体为空时,整个Advice完全不会被调用,包括handleEmptyBody()。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 11:32:49