You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot中读取HttpServletRequest请求体后如何转发同请求至另一端点

网关中重复读取请求体的解决方案

方法一:自定义HttpServletRequestWrapper缓存请求体(Servlet环境)

核心思路:通过包装类缓存已读取的请求体,后续调用getInputStream()/getReader()时直接返回缓存内容

  • 实现步骤:
    1. 编写自定义请求包装类,继承HttpServletRequestWrapper:
      public class CachedBodyHttpServletRequest extends HttpServletRequestWrapper {
          private byte[] cachedBody;
      
          public CachedBodyHttpServletRequest(HttpServletRequest request) throws IOException {
              super(request);
              // 读取原始请求体并缓存
              this.cachedBody = StreamUtils.copyToByteArray(request.getInputStream());
          }
      
          @Override
          public ServletInputStream getInputStream() throws IOException {
              return new CachedServletInputStream(this.cachedBody);
          }
      
          @Override
          public BufferedReader getReader() throws IOException {
              return new BufferedReader(new InputStreamReader(new ByteArrayInputStream(this.cachedBody)));
          }
      
          // 实现自定义ServletInputStream
          private static class CachedServletInputStream extends ServletInputStream {
              private final ByteArrayInputStream inputStream;
      
              public CachedServletInputStream(byte[] cachedBody) {
                  this.inputStream = new ByteArrayInputStream(cachedBody);
              }
      
              @Override
              public int read() throws IOException {
                  return inputStream.read();
              }
      
              @Override
              public boolean isFinished() {
                  return inputStream.available() == 0;
              }
      
              @Override
              public boolean isReady() {
                  return true;
              }
      
              @Override
              public void setReadListener(ReadListener listener) {
                  throw new UnsupportedOperationException("不支持该操作");
              }
          }
      }
      
    2. 编写Filter替换原始请求:
      @WebFilter(filterName = "CachedBodyFilter", urlPatterns = "/*")
      public class CachedBodyFilter implements Filter {
          @Override
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
              HttpServletRequest httpRequest = (HttpServletRequest) request;
              // 用包装类替换原始请求
              CachedBodyHttpServletRequest cachedRequest = new CachedBodyHttpServletRequest(httpRequest);
              chain.doFilter(cachedRequest, response);
          }
      }
      
    3. 启动类添加@ServletComponentScan注解,让Filter生效。

方法二:Spring Cloud Gateway专属方案(响应式环境)

如果使用Spring Cloud Gateway,不要直接操作原生Servlet API,改用WebFlux提供的响应式API处理

  • 编写全局过滤器缓存请求体:
    @Component
    public class RequestBodyCacheFilter implements GlobalFilter, Ordered {
        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            return exchange.getRequest().getBody()
                    .cache() // 缓存请求体,支持重复订阅
                    .flatMap(dataBuffer -> {
                        // 读取请求体并存入数据库
                        byte[] bodyBytes = new byte[dataBuffer.readableByteCount()];
                        dataBuffer.read(bodyBytes);
                        String requestBody = new String(bodyBytes);
                        // 执行数据库存储逻辑
                        // ...
    
                        // 重新构建请求,将缓存的请求体放回
                        ServerHttpRequest newRequest = exchange.getRequest().mutate()
                                .body(BodyInserters.fromValue(bodyBytes))
                                .build();
                        return chain.filter(exchange.mutate().request(newRequest).build());
                    });
        }
    
        @Override
        public int getOrder() {
            return Ordered.HIGHEST_PRECEDENCE; // 确保过滤器最先执行
        }
    }
    

关键注意事项

  • Servlet环境下,Filter的执行顺序必须优先于所有需要读取请求体的组件,保证请求被提前包装。
  • 处理大请求体时,避免内存溢出,可改用临时文件存储缓存内容。
  • Spring Cloud Gateway中禁止混用原生Servlet API,否则会破坏响应式流程,导致后续无法读取请求体。

内容的提问来源于stack exchange,提问作者Ankitha N

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 19:33:22