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

Spring Boot @PostMapping如何同时获取原始Body字符串与对象映射

解决方案

要在Spring中同时实现请求体到对象的自动映射,并且获取原始JSON字符串进行签名验证,核心问题是HttpServletRequest的输入流只能读取一次,直接多次读取会导致报错。可以通过Spring提供的ContentCachingRequestWrapper包装请求,缓存请求体内容,从而实现重复读取。

步骤1:编写请求体缓存过滤器

创建一个过滤器,将请求包装为可缓存请求体的ContentCachingRequestWrapper,确保后续既能让Spring自动反序列化对象,又能获取原始JSON:

import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.ContentCachingRequestWrapper;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CachingRequestBodyFilter extends OncePerRequestFilter {

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        ContentCachingRequestWrapper wrappedRequest = new ContentCachingRequestWrapper(request);
        filterChain.doFilter(wrappedRequest, response);
    }
}

步骤2:注册过滤器

在Spring配置类中注册该过滤器,指定需要应用的接口路径(比如你的/wc-order接口):

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class WebConfig {

    @Bean
    public FilterRegistrationBean<CachingRequestBodyFilter> cachingRequestBodyFilter() {
        FilterRegistrationBean<CachingRequestBodyFilter> registrationBean = new FilterRegistrationBean<>();
        registrationBean.setFilter(new CachingRequestBodyFilter());
        registrationBean.addUrlPatterns("/wc-order");
        return registrationBean;
    }
}

步骤3:修改控制器方法

在控制器中注入HttpServletRequest,将其转为ContentCachingRequestWrapper后即可获取原始请求体字符串,同时保留@RequestBody Order order的自动映射:

@PostMapping(value = "/wc-order")
public void getWcOrder(@RequestBody Order order, @RequestHeader Map<String, String> headers, HttpServletRequest request) {
    String webhookSignature = headers.get("x-wc-webhook-signature");
    
    // 获取原始JSON请求体
    ContentCachingRequestWrapper wrappedRequest = (ContentCachingRequestWrapper) request;
    byte[] rawBodyBytes = wrappedRequest.getContentAsByteArray();
    String plainJsonBody = new String(rawBodyBytes, request.getCharacterEncoding());
    
    String hashedBody = doHMAC(plainJsonBody);
    if (hashedBody.equals(webhookSignature)) {
        // 签名验证通过,执行业务逻辑
    }
}

原理说明

ContentCachingRequestWrapper会在第一次读取请求体时将内容缓存到内部字节数组中,后续无论是Spring MVC的@RequestBody反序列化,还是你手动读取,都会使用缓存的内容,避免了输入流只能读取一次的限制。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 00:16:08