单元返回类型为的Spring-Post方法返回200而不是204
当执行一个返回类型为Unit的方法时,我希望spring不会在响应中的状态代码上添加任何内容,但是它总是返回200ok。有没有办法在全球范围内改变这种行为?我不想向每个单元方法添加ResponseStatus注释单元返回类型为的Spring-Post方法返回200而不是204,spring,spring-boot,kotlin,Spring,Spring Boot,Kotlin,当执行一个返回类型为Unit的方法时,我希望spring不会在响应中的状态代码上添加任何内容,但是它总是返回200ok。有没有办法在全球范围内改变这种行为?我不想向每个单元方法添加ResponseStatus注释 @RestController() @RequestMapping("/{role:(?:veterinarian\\b|admin\\b)}") class EmployeeController( private val userService: UserServic
@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
,@modeldattribute
)
有responseDataAdvice
但没有ResponseStatusAdvice
因此,似乎没有直接的解决方案
解决方法:
这是一个相当肮脏的黑客行为,我真的建议你每次只使用@ResponseStatus,但如果你真的想在全球范围内解决这个问题,那么:
您可以将错误处理和响应建议结合起来
您应该创建一个异常类
class NoContentException: RuntimeException()
为它创建一个处理程序。它应该在@ControllerAdvice
之后调用,这将不会引发ContentException,因此它具有@Order(1)
@ControllerAdvice
@订单(1)
类NoContentErrorHandler{
@ExceptionHandler(NoContentException::类)
fun handleNoContent()=ResponseEntity.noContent().build()
}
最后,创建一个响应主体建议,该建议引发实际异常:
@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()
}
}
@ControllerAdvice
@订单(0)
类ThrowingNoContentExceptionResponseBodyAdvice:ResponseBodyAdvice{
覆盖有趣的支持(returnType:MethodParameter,converterType:Class):布尔{
returnType.parameterType==Void.TYPE
}
在bodywrite之前覆盖乐趣(
主体:单位?,
returnType:MethodParameter,
selectedContentType:MediaType,
selectedConverterType:Class,
请求:ServerHttpRequest,
响应:ServerHttpResponse
):单位{
抛出NoContentException()
}
}
所以它的工作原理是:
请求->带有单元响应调用的方法->抛出异常的建议->处理异常并将其转换为无内容状态的建议请参阅此帖子:有几条建议可能对您有帮助我将尝试使用过滤器调整答案。我添加了一个检查,以确保响应状态为200,这样它就不会干扰身体可能为空的其他响应(如错误)。我希望有一个使用
@ControllerAdvice
的解决方案。我会重新考虑使用@ResponseStatus
,或者尝试使用OncePerRequestFilter
,因为我同意你的观点,这是一种非常肮脏的解决方法。谢谢你的回答
@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()
}
}