SpringBoot请求体缺失异常原因分析与处理方案

 更新时间:2025年10月05日 10:57:37   作者:小猿、  
这篇文章主要介绍了SpringBoot请求体缺失异常原因分析与处理方案,该异常是因为UserController的edit方法缺失了预期的UserUpdatePwdDTO请求体,产生原因主要由前端未发送请求体、Content-Type设置错误或后端缺少@RequestBody注解导致,需要的朋友可以参考下

问题描述

在Spring Boot应用运行过程中,日志中出现如下错误信息:

ERROR c.p.b.f.w.h.GlobalExceptionHandler : 系统内部异常:Required request body is missing: public ... UserController#edit(UserUpdatePwdDTO)

该异常表明在调用UserControlleredit方法时,系统期望接收到一个UserUpdatePwdDTO类型的请求体,但实际请求中缺失了请求体内容。

异常原因分析

1. 根本原因

此异常通常由以下情况引起:

  1. 前端未发送请求体:前端发起请求时没有包含必要的JSON数据
  2. Content-Type设置错误:未正确设置application/json头部
  3. 方法参数注解缺失:后端控制器方法缺少@RequestBody注解
  4. 空请求体:请求体存在但内容为空

2. 技术背景

Spring MVC框架通过@RequestBody注解将HTTP请求体映射到方法参数。当使用该注解时,Spring期望每个请求都必须包含非空的请求体。

解决方案

1. 前端修复方案

确保正确设置请求头和请求体:

// Axios示例
axios.put('/api/user/edit', {
  oldPassword: 'currentPassword123',
  newPassword: 'newPassword456'
}, {
  headers: {
    'Content-Type': 'application/json'
  }
})
// Fetch API示例
fetch('/api/user/edit', {
  method: 'PUT',
  headers: {
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    oldPassword: 'currentPassword123',
    newPassword: 'newPassword456'
  })
})

2. 后端修复方案

方案一:添加参数验证和默认处理

@RestController
@RequestMapping("/api/user")
public class UserController {
    @PutMapping("/edit")
    public ResponseEntity<?> edit(@RequestBody(required = false) UserUpdatePwdDTO dto) {
        if (dto == null) {
            return ResponseEntity.badRequest().body("请求体不能为空");
        }
        // 业务逻辑处理
        userService.updatePassword(dto);
        return ResponseEntity.ok("密码修改成功");
    }
}

方案二:使用全局异常处理增强

@ControllerAdvice
public class GlobalExceptionHandler {
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public ResponseEntity<ErrorResponse> handleHttpMessageNotReadable(
            HttpMessageNotReadableException ex) {
        logger.error("请求体解析异常: {}", ex.getMessage());
        ErrorResponse errorResponse = new ErrorResponse();
        errorResponse.setCode("BAD_REQUEST");
        errorResponse.setMessage("请求参数格式错误或请求体缺失");
        errorResponse.setTimestamp(LocalDateTime.now());
        return ResponseEntity.badRequest().body(errorResponse);
    }
    // 错误响应DTO
    @Data
    public static class ErrorResponse {
        private String code;
        private String message;
        private LocalDateTime timestamp;
    }
}

方案三:自定义验证注解

@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface OptionalRequestBody {
    // 自定义注解用于可选请求体
}
// 对应的解析器
public class OptionalRequestBodyResolver implements HandlerMethodArgumentResolver {
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        return parameter.hasParameterAnnotation(OptionalRequestBody.class);
    }
    @Override
    public Object resolveArgument(MethodParameter parameter, 
                                 ModelAndViewContainer mavContainer,
                                 NativeWebRequest webRequest, 
                                 WebDataBinderFactory binderFactory) throws Exception {
        // 自定义解析逻辑
        return null; // 根据实际情况实现
    }
}

3. DTO类优化

添加合理的默认值和验证规则:

@Data
public class UserUpdatePwdDTO {
    @NotBlank(message = "旧密码不能为空")
    private String oldPassword;
    @NotBlank(message = "新密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间")
    private String newPassword;
    // 默认构造函数
    public UserUpdatePwdDTO() {}
    // 全参构造函数
    public UserUpdatePwdDTO(String oldPassword, String newPassword) {
        this.oldPassword = oldPassword;
        this.newPassword = newPassword;
    }
}

预防措施

1. 接口文档规范

  1. 明确标注需要请求体的接口
  2. 提供完整的请求示例
  3. 说明Content-Type要求

2. 测试策略

@SpringBootTest
@AutoConfigureTestDatabase
class UserControllerTest {
    @Autowired
    private TestRestTemplate restTemplate;
    @Test
    void shouldReturnBadRequestWhenBodyMissing() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> request = new HttpEntity<>(null, headers);
        ResponseEntity<String> response = restTemplate
            .exchange("/api/user/edit", HttpMethod.PUT, request, String.class);
        assertEquals(HttpStatus.BAD_REQUEST, response.getStatusCode());
    }
}

3. 前端统一拦截器

// 请求拦截器
axios.interceptors.request.use(config => {
  if (['POST', 'PUT', 'PATCH'].includes(config.method.toUpperCase())) {
    if (!config.headers['Content-Type']) {
      config.headers['Content-Type'] = 'application/json';
    }
  }
  return config;
});
// 响应拦截器 - 统一处理400错误
axios.interceptors.response.use(
  response => response,
  error => {
    if (error.response?.status === 400) {
      // 统一处理请求体缺失等错误
      showErrorMessage('请求参数错误,请检查后重试');
    }
    return Promise.reject(error);
  }
);

总结

Required request body is missing异常是Spring Boot应用中常见的错误,通常由前后端协作不当引起。通过本文提供的解决方案,可以从以下几个方面全面解决该问题:

  1. 前端确保:正确设置请求头和请求体
  2. 后端增强:合理的异常处理和参数验证
  3. 团队协作:完善的接口文档和测试策略
  4. 监控预警:日志记录和异常监控

通过系统性的解决方案,可以有效避免此类异常的发生,提升系统的稳定性和开发效率。

以上就是SpringBoot请求体缺失异常原因分析与处理方案的详细内容,更多关于SpringBoot请求体缺失的资料请关注脚本之家其它相关文章!

相关文章

  • JetBrains IntelliJ IDEA 配置优化技巧

    JetBrains IntelliJ IDEA 配置优化技巧

    这篇文章主要介绍了JetBrains IntelliJ IDEA 配置优化技巧,本文通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2020-12-12
  • Java实战之王者荣耀的英雄是怎么产生的?

    Java实战之王者荣耀的英雄是怎么产生的?

    这篇文章主要介绍了Java实战之王者荣耀的英雄是怎么产生的?文中有非常详细的代码示例,对正在学习java的小伙伴们有很好地帮助,需要的朋友可以参考下
    2021-05-05
  • Spring中的@ConfigurationProperties详解

    Spring中的@ConfigurationProperties详解

    这篇文章主要介绍了Spring中的@ConfigurationProperties详解,ConfigurationProperties注解主要用于将外部配置文件配置的属性填充到这个Spring Bean实例中,需要的朋友可以参考下
    2023-09-09
  • Java单例模式分析

    Java单例模式分析

    这篇文章主要给大家介绍了关于Java单例模式,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2021-09-09
  • 解决@Scope(“prototype“)不生效的问题

    解决@Scope(“prototype“)不生效的问题

    这篇文章主要介绍了解决@Scope(“prototype“)不生效的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-06-06
  • 快速上手Java单元测试框架JUnit5

    快速上手Java单元测试框架JUnit5

    今天给大家带来的是关于Java单元测试的相关知识,文章围绕着Java单元测试框架JUnit5展开,文中有非常详细的介绍及代码示例,需要的朋友可以参考下
    2021-06-06
  • 打印Java程序的线程栈信息方式

    打印Java程序的线程栈信息方式

    这篇文章主要介绍了打印Java程序的线程栈信息方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-09-09
  • JDBC基础教程

    JDBC基础教程

    这篇文章主要介绍了JDBC基础知识与操作技巧,讲述原理与基本技巧的基础上分析了安全问题与操作注意事项,非常具有实用价值,需要的朋友可以参考下
    2014-12-12
  • 浅谈JDK7和JDK8的区别在哪

    浅谈JDK7和JDK8的区别在哪

    面试总是遇到这个问题,做一个小总结,文中有非常详细的介绍,对正在学习java的小伙伴们很有帮助,需要的朋友可以参考下
    2021-06-06
  • 浅谈Java方法的重载

    浅谈Java方法的重载

    方法重载是指在一个类中定义多个同名的方法,但要求每个方法具有不同的参数的类型或参数的个数。调用重载方法时,Java编译器能通过检查调用的方法的参数类型和个数选择一个恰当的方法。方法重载通常用于创建完成一组任务相似但参数的类型或参数的个数不同的方法。
    2016-04-04

最新评论