Получить тело запроса на @RestControllerAdvise - PullRequest
1 голос
/ 13 февраля 2020

Я настраиваю пользовательскую обработку ошибок, чтобы регистрировать каждый неверный запрос в моем API. В моем сценарии важно знать полезную нагрузку, переданную в запросе, чтобы я мог исправить / протестировать / обработать ее по мере необходимости.

Я построил простую @RestControllerAdvise, но мне трудно получить тело запроса от него:

@RestControllerAdvice
class ExceptionHandler {

    companion object {
        private val logger = getLogger()
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    fun badRequest(e: Exception, request: HttpServletRequest): Exception {
        logger.error("Received a bad request with body: ${request.getBodyPlease()}", e) // Note getBodyPlease() is not a real method
        return e
    }
}

Я попытался прочитать InputStream из запроса, но на данный момент он уже закрыт. Другой вопрос предлагает ввести RequestContext и установить его на Controller. Это не сработает в сценарии Bad Request, поскольку не выполнит контроллер. Также не имеет смысла устанавливать его в каждом контроллере.

Заранее спасибо,

Редактировать

Как предложил @BeUndead, я попытался реализовать фильтр для переноса запроса:

@Component
class RequestWrapperFilter : Filter {
    override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {
        val reqWrapper = ContentCachingRequestWrapper(req as HttpServletRequest)
        chain.doFilter(reqWrapper, res)
    }
}

Затем я пытаюсь получить тело вроде request.reader.lines().collect(Collectors.joining()). Когда я примеряю фильтр, с ServletRequest он работает нормально, я вижу тело. Но когда я примеряю @ExceptionHandler с ContentCachingRequestWrapper, я получаю пустую строку,

1 Ответ

0 голосов
/ 13 февраля 2020

В соответствии с предложением @BeUndead, я реализовал фильтр для переноса запроса в ContentCachingRequestWrapper:

@Component
class RequestWrapperFilter : Filter {
    override fun doFilter(req: ServletRequest, res: ServletResponse, chain: FilterChain) {
        val reqWrapper = ContentCachingRequestWrapper(req as HttpServletRequest)
        chain.doFilter(reqWrapper, res)
    }
}

И затем я могу подготовить тело столько раз, сколько я хочу от contentAsByteArrayProperty:

@RestControllerAdvice
class ExceptionHandler {

    companion object {
        private val logger = getLogger()
    }

    @ExceptionHandler
    @ResponseStatus(HttpStatus.BAD_REQUEST)
    fun badRequest(e: Exception, request: HttpServletRequest): Exception {
        val body = (request as ContentCachingRequestWrapper).contentAsByteArray.toString(Charsets.UTF_8)
        logger.error("Received a bad request with body: $body", e)
        return e
    }
}
...