spring阅读请求正文两次


问题内容

在spring,我有一个带有端点的控制器,如下所示:

@RequestMapping(method = RequestMethod.POST)
@ResponseStatus(HttpStatus.CREATED)
@ResponseBody
public OutputStuff createStuff(@RequestBody Stuff stuff) {
    //my logic here
}

这样,如果对此端点执行POST,请求主体中的JSON将自动反序列化到我的模型(Stuff)。问题是,我只需要记录即将传入的原始JSON!我尝试了不同的方法。

  1. 注射HttpServletRequestcreateStuff读体内有和日志:

码:

@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
}

问题在于,当我执行此操作时,将已经执行了读者的InputStream来将JSON反序列化为Stuff。所以我会得到一个错误,因为我无法两次读取相同的输入流。

  1. 使用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;
    }
}

这个问题是,当反序列化stuff发生时,来自请求的InputStream已经被读取!因此,我将再次获得例外。

  1. 我考虑过但尚未实现的另一个选项是以某种方式迫使Spring使用我的自定义实现,HttpServletRequest该实现将缓存输入流并允许对其进行多次读取。我不知道这是否可行,我找不到任何文档或示例!

  2. 还有一种选择是不读取Stuff我的端点,而是将请求正文读取为String,将其记录下来,然后反序列化为Stuff使用ObjectMapper或类似的东西。我也不喜欢这个想法。

有没有我没有提到和/或不知道的更好的解决方案?我将不胜感激。我正在使用最新版本的SpringBoot。


问题答案:

如何在文件中记录HttpRequest和HttpResponse?,spring提供了AbstractRequestLoggingFilter,可用于记录请求。

在此处找到
AbstractRequestLoggingFilter
API文档