具有 Unit 返回类型的 Spring Post 方法返回 200 而不是 204



当执行返回类型为 Unit 的方法时,我希望 spring 在响应中的状态代码上放置 204 NO CONTENT,但它总是返回 200 OK。有没有办法改变全球范围内的这种行为?我不想向每个单元方法添加响应状态注释。

@RestController()
@RequestMapping("/{role:(?:veterinarian\b|admin\b)}")
class EmployeeController(
private val userService: UserService
) {
@PostMapping(consumes = [MediaType.APPLICATION_JSON_UTF8_VALUE])
fun hire(@RequestBody employeeDTO: EmployeeDTO, @PathVariable role: String): Unit {
if (employeeDTO.user_role != role)
throw ResponseStatusException(HttpStatus.BAD_REQUEST)
else
userService.addNewUser(EmployeeDAO.build(employeeDTO))
}
}

更新:

我最终使用过滤器来检查当状态响应为 200 OK 并且它似乎有效时内容类型是否未定义。

这是过滤器代码

@Component
public class NoContentFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
filterChain.doFilter(httpServletRequest, httpServletResponse);
if (httpServletResponse.getContentType() == null ||
httpServletResponse.getContentType().equals("")) {
if ( httpServletResponse.getStatus() == 200 ) {
httpServletResponse.setStatus(HttpStatus.NO_CONTENT.value());
}
}
}
}

Spring 允许通过 @ControllerAdvice 配置控制器的全局行为

用@ControllerAdvice批注的类可以包含@ExceptionHandler、@InitBinder和@ModelAttribute带批注的方法,这些方法将应用于所有控制器层次结构中的@RequestMapping方法,而不是声明它们的控制器层次结构。

通常,我们使用它来处理全局异常@ExceptionHandler但事实并非如此。(@InitBinder@ModelAttribute也是(

ResponseBodyAdvice但没有ResponseStatusAdvice

所以似乎没有直接的解决方案

解决方法:

这是一个非常肮脏的黑客,我真的建议您每次都使用@ResponseStatus,但如果您真的想在全球范围内解决这个问题,那么:

您可以结合错误处理和 ResponseBodyAdvice

您应该创建一个异常类

class NoContentException: RuntimeException()

为其创建一个处理程序。它应该在@ControllerAdvice之后调用,这将抛出 NoContentException,以便它@Order(1)

@ControllerAdvice
@Order(1)
class NoContentErrorHandler {
@ExceptionHandler(NoContentException::class)
fun handleNoContent() = ResponseEntity.noContent().build<Unit>()
}

最后创建一个响应正文建议,该建议会抛出实际的异常:

@ControllerAdvice
@Order(0)
class ThrowingNoContentExceptionResponseBodyAdvice : ResponseBodyAdvice<Unit> {
override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean {
return returnType.parameterType == Void.TYPE
}
override fun beforeBodyWrite(
body: Unit?,
returnType: MethodParameter,
selectedContentType: MediaType,
selectedConverterType: Class<out HttpMessageConverter<*>>,
request: ServerHttpRequest,
response: ServerHttpResponse
): Unit? {
throw NoContentException()
}
}

所以它的工作原理是这样的: request -> 方法与 Unit 响应调用 ->引发异常的建议 ->处理异常并将其转换为NO_CONTENT状态

的建议

最新更新