Dan*_*zyk 6 logging spring spring-mvc
在春天,我有一个带有端点的控制器,如下所示:
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public OutputStuff createStuff(@RequestBody Stuff stuff) {
//my logic here
}
Run Code Online (Sandbox Code Playgroud)
这样,如果在此端点上执行 POST,请求正文中的 JSON 将自动反序列化为我的模型 ( Stuff)。问题是,我只是需要在原始 JSON 传入时记录它!我尝试了不同的方法。
HttpServletRequest入createStuff读体内有和日志:代码:
@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public OutputStuff createStuff(@RequestBody Stuff stuff, HttpServletRequest req) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
//my logic here
}
Run Code Online (Sandbox Code Playgroud)
问题在于,当我执行此操作时,读取器的 InputStream 已被执行以将 JSON 反序列化为Stuff. 所以我会得到一个错误,因为我不能两次读取相同的输入流。
HandlerInterceptorAdapter将在调用实际处理程序之前记录原始 JSON 的自定义。 代码(部分):
public class RawRequestLoggerInterceptor extends HandlerInterceptorAdapter {
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
StringBuilder sb = new StringBuilder();
req.getReader().getLines().forEach(line -> {
sb.append(line);
});
//log sb.toString();
return true;
}
}
Run Code Online (Sandbox Code Playgroud)
这个问题是,当反序列化stuff发生时,来自请求的 InputStream 已经被读取了!所以我会再次得到一个例外。
我考虑过但尚未实现的另一种选择是以某种方式迫使 Spring 使用我的自定义实现HttpServletRequest来缓存输入流并允许对其进行多次读取。我不知道这是否可行,而且我找不到任何文档或示例!
另一种选择是不在Stuff我的端点上读取,而是将请求正文读取为String,记录它然后将其反序列化为StuffusingObjectMapper或类似的东西。我也不喜欢这个想法。
有没有更好的解决方案,我没有提到和/或不知道?我将不胜感激。我正在使用最新版本的 SpringBoot。
要多次读取请求正文,我们必须缓存初始负载。因为一旦原始的InputStream被消耗,我们就无法再次读取它。
首先,Spring MVC提供了ContentCachingRequestWrapper类来存储原始内容。因此,我们可以调用getContentAsByteArray()方法多次检索正文。
因此,在您的情况下,您可以在过滤器中使用此类:
@Component
public class CachingRequestBodyFilter extends GenericFilterBean {
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest currentRequest = (HttpServletRequest) servletRequest;
ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(currentRequest);
// Other details
chain.doFilter(wrappedRequest, servletResponse);
}
}
Run Code Online (Sandbox Code Playgroud)
或者,您可以在应用程序中注册CommonsRequestLoggingFilter 。此过滤器在幕后使用ContentCachingRequestWrapper,旨在记录请求。
正如这篇文章中所引用的:How to Log HttpRequest and HttpResponse in a file? ,spring提供了AbstractRequestLoggingFilter,你可以用它来记录请求。
AbstractRequestLoggingFilter API 文档,可在此处找到
| 归档时间: |
|
| 查看次数: |
14745 次 |
| 最近记录: |