我使用的是 Boot ,其中包含spring-web-4.3.3。我有一个用@ControllerAdvice
注解的类和用@ExceptionHandler
注解的方法来处理服务代码引发的异常。在处理这些异常时,我希望记录PUT和POST操作请求中的@RequestBody
,以便查看导致问题的请求主体,该请求主体位于我病例对诊断至关重要。
根据Spring Docs,@ExceptionHandler
方法的方法签名可以包括各种东西,包括HttpServletRequest
。请求主体通常可以通过getInputStream()
或getReader()
从这里获得,但是如果我的控制器方法像我的所有方法一样解析"@RequestBody Foo fooBody"
的请求主体,HttpServletRequest's
输入流或读取器在调用我的异常处理程序方法时已经关闭。与here描述的问题类似。使用servlet时,请求主体只能读取一次,这是一个常见的问题。
不幸的是,@RequestBody
不是异常处理方法可用的选项之一,如果是的话,我可以使用它。
我可以将InputStream
添加到异常处理程序方法中,但这最终与HttpServletRequest的InputStream是一样的,因此存在相同的问题。
我还尝试使用((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest()
获取当前请求,这是获取当前请求的另一个技巧,但这最终是Spring传递到异常处理程序方法中的同一个HttpServletRequest,因此存在相同的问题。
我读过一些解决方案,如this和this,它们涉及在过滤器链中插入一个自定义请求 Package 器,该 Package 器将读取请求的内容并缓存它们,以便可以多次读取它们。(并可能引入性能或稳定性问题),并且如果我有任何大型请求(如上传的文档)另外,Spring可能已经在某个地方缓存了@RequestBody
,如果我能找到它的话。
顺便说一句,许多解决方案建议使用ContentCachingRequestWrapper
Spring类,但根据我的经验,这并不起作用。除了没有被记录,看它的源代码,它看起来只缓存了参数,而不是请求主体。试图从这个类中获取请求主体总是导致一个空字符串。
所以我正在寻找任何其他的选择,我可能已经错过了。谢谢阅读。
6条答案
按热度按时间nue99wik1#
Accepted answer创建一个新的POJO来传递内容,但是通过重用http请求,无需创建额外的对象也可以实现相同的行为。
控制器Map的示例代码:
稍后在ExceptionHandler类/方法中,您可以用途:
3j86kqsm2#
您可以将请求主体对象引用到请求作用域Bean。然后将该请求作用域Bean注入到异常处理程序中,以检索请求主体(或要引用的其他请求上下文Bean)。
k5ifujac3#
您应该能够通过使用RequestBodyAdvice接口来获取请求主体的内容。如果您在一个用@ControllerAdvice注解的类上实现了这个接口,它应该会被自动获取。
为了获取其他请求信息,比如HTTP方法和查询参数,我使用了一个interceptor。我在ThreadLocal变量中捕获了所有这些请求信息,以用于错误报告,我在同一个拦截器的afterCompletion钩子上清除了这个变量。
下面的类实现了这一点,并且可以在ExceptionHandler中使用该类来获取所有请求信息:
rpppsulh4#
下面是我用于某些字段验证控件的Kotlin语法解决方案。
我需要增强
@RestControllerAdvice
的默认handleMethodArgumentNotValid(...)
方法,以便系统地记录嵌入在同一请求主体对象中的字段。2ledvvac5#
只是对quintencl的答案的增强
我得到了请求主体,可以在异常处理程序类中的任何地方使用它。
scyqe7ek6#
请参见此处:https://stackoverflow.com/a/61813076/1036433-获取访问HttpServerRequest的干净方法。