如何让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
相关产品推荐
相关产品推荐

