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

如何让Spring在无请求体接口收到请求体时抛出错误?

解决方案

针对你的需求,有几种可靠方式可以实现当接口收到请求体时抛出错误:

方案1:单接口直接校验(简洁高效)

在控制器方法中注入HttpServletRequest,通过检查请求内容长度或输入流判断是否存在请求体,若存在则手动抛出异常:

@RestController
@RequestMapping("/test")
public class TestController {
    @PostMapping
    public String handler(HttpServletRequest request) throws IOException {
        // 检查请求是否携带请求体
        if (request.getContentLengthLong() > 0) {
            throw new HttpMessageNotReadableException("该接口不允许携带请求体");
        }
        // 额外处理分块传输场景(部分请求Content-Length可能为0但实际有内容)
        ServletInputStream inputStream = request.getInputStream();
        if (inputStream.available() > 0) {
            throw new HttpMessageNotReadableException("该接口不允许携带请求体");
        }
        return "success";
    }
}

抛出的HttpMessageNotReadableException会被Spring自动转换为400 Bad Request响应,无需额外处理。

方案2:通过@RequestBody参数校验(代码更简洁)

添加一个@RequestBody(required = false)的参数,若该参数不为空(即存在可解析的请求体)则抛出异常:

@RestController
@RequestMapping("/test")
public class TestController {
    @PostMapping
    public String handler(@RequestBody(required = false) String requestBody) {
        if (requestBody != null && !requestBody.trim().isEmpty()) {
            throw new HttpMessageNotReadableException("该接口不允许携带请求体");
        }
        return "success";
    }
}

这种方式无需操作原生请求对象,但依赖Spring默认的消息转换器能力,若请求体是无法被解析的二进制流,可能无法触发校验。

方案3:自定义拦截器(多接口/全局适用)

如果需要对多个接口统一做“禁止请求体”的限制,可以自定义拦截器,在请求到达控制器前完成校验:

1. 实现拦截器逻辑

@Component
public class NoRequestBodyInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        // 判断当前接口是否声明了@RequestBody参数
        boolean hasRequestBodyParam = Arrays.stream(handlerMethod.getMethodParameters())
                .anyMatch(param -> param.hasParameterAnnotation(RequestBody.class));

        // 仅针对POST请求、且未声明@RequestBody的接口做校验
        if ("POST".equals(request.getMethod()) && !hasRequestBodyParam) {
            long contentLength = request.getContentLengthLong();
            boolean hasBody = contentLength > 0;
            
            // 处理Content-Length为0但实际有请求体的分块传输场景
            if (!hasBody) {
                ServletInputStream inputStream = request.getInputStream();
                hasBody = inputStream.read() != -1;
                // 若读取到内容,重置流避免后续处理异常(可使用ContentCachingRequestWrapper优化)
                if (hasBody) {
                    request.setAttribute("cachedRequestBody", new ByteArrayInputStream(new byte[]{(byte) inputStream.read()}));
                }
            }

            if (hasBody) {
                response.sendError(HttpServletResponse.SC_BAD_REQUEST, "该接口不允许携带请求体");
                return false;
            }
        }
        return true;
    }
}

2. 注册拦截器

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    @Autowired
    private NoRequestBodyInterceptor noRequestBodyInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(noRequestBodyInterceptor)
                .addPathPatterns("/test"); // 指定生效路径,改为/**可全局生效
    }
}

这种方式适合批量管理接口规则,无需逐个修改控制器代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.24 12:24:58