SpringBoot POST请求测试中Handler未识别的原因及解决方法
SpringBoot测试问题排查:Handler Type为Null且403 Forbidden错误
问题描述
测试接收JSON格式数据的POST控制器方法时,出现handler: type = null提示,同时返回403 Forbidden错误。
测试代码
@WebMvcTest(QuizController.class) public class QuizControllerTest { @MockBean private QuizRepository quizRepository; @Autowired private MockMvc mockMvc; @Autowired private ObjectMapper objectMapper; @Test void shouldAddQuestion() throws Exception { QuizDTO quizDTO = new QuizDTO(104, "epidemics", 21, 4, "Test Question?", "A", "B", "C", "D", "hint"); ObjectMapper objectMapper = new ObjectMapper(); String json = objectMapper.writeValueAsString(quizDTO); mockMvc.perform(post("/adminadd") .with(user("admin").password("password").roles("USER")) .contentType(MediaType.APPLICATION_JSON) .content(json)) .andExpect(status().isCreated()) .andDo(print()); } }
控制器代码
@PostMapping("/adminadd") public QuizDTO addQuestion(@RequestBody QuizDTO quizDTO) { return quizRepo.addQuestion(quizDTO); }
错误信息
MockHttpServletRequest: HTTP Method = POST Request URI = /adminadd Parameters = {} Headers = [Content-Type:"application/json;charset=UTF-8", Content-Length:"175"] Body = {"type":"epidemics","questionIndex":21,"choiceNum":4,"question":"Test Question?","choiceA":"A","choiceB":"B","choiceC":"C","choiceD":"D","correct":null,"hint":"hint","id":104} Session Attrs = {org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN=org.springframework.security.web.csrf.DefaultCsrfToken@5bde6148, SPRING_SECURITY_CONTEXT=SecurityContextImpl [Authentication=UsernamePasswordAuthenticationToken [Principal=org.springframework.security.core.userdetails.User [Username=admin, Password=[PROTECTED], Enabled=true, AccountNonExpired=true, credentialsNonExpired=true, AccountNonLocked=true, Granted Authorities=[ROLE_USER]], Credentials=[PROTECTED], Authenticated=true, Details=null, Granted Authorities=[ROLE_USER]]]} Handler: Type = null
MockHttpServletResponse: Status = 403 Error message = Forbidden Headers = [X-Content-Type-Options:"nosniff", X-XSS-Protection:"1; mode=block", Cache-Control:"no-cache, no-store, max-age=0, must-revalidate", Pragma:"no-cache", Expires:"0", X-Frame-Options:"DENY"] Content type = null Body = Forwarded URL = null Redirected URL = null Cookies = []
问题原因分析
1. handler: type = null的核心原因
- 控制器未被识别为请求处理器:你的控制器代码仅添加了
@PostMapping方法注解,但缺少@RestController或@Controller类级注解,导致@WebMvcTest无法扫描到该类作为Spring MVC控制器Bean,自然找不到对应请求的处理器。 - 请求路径不匹配:如果控制器类上存在
@RequestMapping前缀(比如@RequestMapping("/api")),而测试请求用的是/adminadd,会导致路径不匹配,无法定位到处理器。 - Security拦截优先:403权限拦截发生在请求映射匹配之前,导致请求从未到达控制器匹配阶段,因此显示处理器类型为null。
2. 403 Forbidden的原因
测试中使用的用户角色是USER,但/adminadd接口大概率需要更高权限(比如ADMIN角色),而你的Security配置可能限制了该路径仅允许ADMIN角色访问,因此触发权限拦截。
解决方案
步骤1:修复控制器注解
给QuizController添加@RestController注解(如果是返回JSON的REST接口),确保Spring能识别它为控制器:
@RestController // 添加类级注解 public class QuizController { @Autowired private QuizRepository quizRepo; @PostMapping("/adminadd") public QuizDTO addQuestion(@RequestBody QuizDTO quizDTO) { return quizRepo.addQuestion(quizDTO); } }
步骤2:修正测试用户角色
如果/adminadd接口需要ADMIN权限,测试中使用的用户角色要改为ADMIN:
mockMvc.perform(post("/adminadd") .with(user("admin").password("password").roles("ADMIN")) // 替换为ADMIN角色 .contentType(MediaType.APPLICATION_JSON) .content(json))
步骤3:验证请求路径一致性
检查控制器类是否有@RequestMapping前缀,比如:
@RestController @RequestMapping("/api") // 假设存在路径前缀 public class QuizController { @PostMapping("/adminadd") public QuizDTO addQuestion(@RequestBody QuizDTO quizDTO) { return quizRepo.addQuestion(quizDTO); } }
此时测试请求路径要改为/api/adminadd:
mockMvc.perform(post("/api/adminadd") ... )
步骤4:(可选)调试时关闭Security拦截
如果需要快速验证控制器逻辑,可在测试中关闭所有过滤器(包括CSRF和权限拦截):
@WebMvcTest(QuizController.class) @AutoConfigureMockMvc(addFilters = false) // 仅用于调试,正式测试建议保留权限验证 public class QuizControllerTest { // ... 测试代码 }
步骤5:优化ObjectMapper使用
测试中已经通过@Autowired注入了ObjectMapper,无需重新实例化:
// 移除这句:ObjectMapper objectMapper = new ObjectMapper(); String json = this.objectMapper.writeValueAsString(quizDTO);
内容的提问来源于stack exchange,提问作者SW2022
相关产品推荐
相关产品推荐

