在春天,我有一个控制器,其端点如下:
Here is the code that I used
function myFunction(e){
var userName = e.values[1];
var userEmail = e.values[2];
var score = e.values[3];
var subject = "Thank you for your participation: Find your Score";
var message = "Thank you, " + userName + " for choosing to participate in this test. Your score is " +score;
MailApp.sendEmail (userEmail, subject, message);}
这样,如果在此端点上执行POST,请求正文中的JSON将自动反序列化为我的模型(@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public OutputStuff createStuff(@RequestBody Stuff stuff) {
//my logic here
}
)。问题是,我刚要求记录原始JSON,因为它正在进入!我尝试了不同的方法。
Stuff
注入HttpServletRequest
,在那里阅读正文并记录:代码:
createStuff
这个问题是,当我执行它时,读者的InputStream已经被执行以将JSON反序列化为@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
}
。所以我会收到一个错误,因为我无法读取相同的输入流两次。
Stuff
。 代码(部分内容):
HandlerInterceptorAdapter
这个问题是,当反序列化到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;
}
}
时,请求的InputStream已经被读取了!所以我会再次得到一个例外。
我考虑的另一个选项,但尚未实现,将以某种方式迫使Spring使用我的stuff
自定义实现,它将缓存输入流并允许多次读取它。我不知道这是否可行,我无法找到任何文档或示例!
另一种选择是不在我的端点上阅读HttpServletRequest
,而是将请求正文读作Stuff
,记录它,然后使用{将其反序列化为String
{1}}或类似的东西。我不喜欢这个想法。
有没有更好的解决方案,我没有提及和/或我不知道?我很感激帮助。我正在使用最新版本的SpringBoot。
答案 0 :(得分:3)
正如本文所述:How to Log HttpRequest and HttpResponse in a file?,spring提供了可用于记录请求的AbstractRequestLoggingFilter。
AbstractRequestLoggingFilter API文档,found here
答案 1 :(得分:0)
对于read the request body multiple times,我们必须缓存初始有效负载。因为一旦使用完原始的 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);
}
}
或者,您可以在应用程序中注册 CommonsRequestLoggingFilter 。此过滤器在幕后使用 ContentCachingRequestWrapper ,并且是为logging the requests设计的。