Spring Post Method с типом возврата Unit возвращает 200 вместо 204 - PullRequest
0 голосов
/ 19 октября 2019

При выполнении метода с возвращаемым типом Unit я бы ожидал, что пружина поместит 204 NO CONTENT в код состояния в ответе, однако всегда возвращает 200 OK. Есть ли способ изменить это поведение в глобальном покое? Я не хочу добавлять аннотации ResponseStatus к каждому методу Unit.

@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 ОК, и, кажется, работает.

Это код фильтра

@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 голосов
/ 20 октября 2019

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

Таким образом, он работает следующим образом: запрос -> метод с ответным вызовом модуля -> рекомендация, выдающая исключение -> рекомендация, обрабатывающая исключение и преобразующая его в состояние NO_CONTENT

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...