gpt4 book ai didi

Spring 阅读请求正文两次

转载 作者:行者123 更新时间:2023-12-03 16:06:27 28 4
gpt4 key购买 nike

在 Spring ,我有一个带有这样端点的 Controller :

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

这样,如果在此端点上执行 POST,请求正文中的 JSON 将自动反序列化为我的模型 ( Stuff)。问题是,我只是要求在原始 JSON 输入时记录它!我尝试了不同的方法。
  • 注入(inject) 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
    }

    这样做的问题是,当我执行此操作时,阅读器的 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;
    }
    }

    这个问题是,当反序列化到 stuff 时发生时,请求中的 InputStream 已经被读取了!所以我会再次得到一个异常(exception)。
  • 我考虑过但尚未实现的另一个选项是强制 Spring 使用我的自定义实现 HttpServletRequest这将缓存输入流并允许对其进行多次读取。我不知道这是否可行,也找不到任何文档或示例!
  • 另一种选择是不阅读Stuff。在我的端点上,而是将请求正文读取为 String , 记录它然后反序列化到 Stuff使用 ObjectMapper或类似的东西。我也不喜欢这个主意。

  • 有没有更好的解决方案,我没有提到和/或不知道?我会很感激帮助。我正在使用最新版本的 SpringBoot。

    最佳答案

    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 设计。 .

    关于 Spring 阅读请求正文两次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32763922/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com