我使用的是Spring Boot 1.4.1,其中包括spring-web-4.3.3 . 我有一个用 @ControllerAdvice
注释的类和用 @ExceptionHandler
注释的方法来处理服务代码抛出的异常 . 在处理这些异常时,我想记录作为PUT和POST操作请求的一部分的 @RequestBody
,这样我就可以看到导致问题的请求体,在我的情况下,这对于诊断至关重要 .
每Spring Docs @ExceptionHandler
方法的方法签名可以包括各种内容,包括 HttpServletRequest
. 请求体通常可以通过 getInputStream()
或 getReader()
从这里获得,但是如果我的控制器方法像_1293215那样解析请求体,那么 HttpServletRequest's
输入流或读取器在调用异常处理程序方法时已经关闭 . 本质上,Spring已经读取了请求主体,类似于here描述的问题 . 使用servlet是一个常见问题,请求体只能读取一次 .
不幸的是 @RequestBody
不是异常处理程序方法可用的选项之一,如果是那时我可以使用它 .
我可以在异常处理程序方法中添加 InputStream
,但最终与HttpServletRequest的InputStream相同,因此具有相同的问题 .
我也尝试使用 ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
获取当前请求,这是获取当前请求的另一个技巧,但这最终与Spring传递到异常处理程序方法的HttpServletRequest相同,因此也存在同样的问题 .
我已经阅读了一些像this和this这样的解决方案,它们涉及在过滤器链中插入一个自定义请求包装器,它将读取请求的内容并缓存它们,以便可以多次读取它们 . 我不想中断整个过滤器/请求/响应链(并可能引入性能或稳定性问题)只是为了实现日志记录,如果我有任何大的请求,如上传的文件(我这样做),我不想要将其缓存在内存中 . 此外,如果我只能找到它,Spring可能已经在某处缓存了 @RequestBody
.
顺便提一下,许多解决方案建议使用 ContentCachingRequestWrapper
Spring类,但根据我的经验,这不起作用 . 除了没有记录之外,查看其源代码看起来它只是缓存参数,而不是请求体 . 尝试从此类获取请求正文总是会产生一个空字符串 .
所以我正在寻找我可能错过的任何其他选择 . 谢谢阅读 .
2 回答
您可以将请求正文对象引用到请求范围的bean . 然后在您的异常处理程序中注入请求范围的bean以检索请求主体(或您希望引用的其他请求上下文bean) .
接受的答案会创建一个新的POJO来传递内容,但是通过重用http请求可以在不创建其他对象的情况下实现相同的行为 .
Controller映射的示例代码:
稍后在ExceptionHandler类/方法中,您可以使用: