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

时间:2019-10-19 18:40:13

标签: spring spring-boot kotlin

当执行返回类型为Unit的方法时,我希望弹簧将204 NO CONTENT放在响应的状态代码上,但是它总是返回200 OK。有什么办法可以在全球范围内改变这种行为?我不想向每个Unit方法添加ResponseStatus批注。

@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());
            }
        }
    }
}

1 个答案:

答案 0 :(得分:0)

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 response调用的方法->引发异常的建议->处理异常并将其转换为NO_CONTENT状态的建议