spring boot 处理 request body中重复消费

spring boot 处理 request body中重复消费

场景

  • 验签取参数,取完之后下游需要两次从 request 中获取body数据
  • 请求日志

解决方案

缓存 request body 数据,然后向下传递

RepeatableHttpRequestWrapper
public class RepeatableHttpRequestWrapper extends HttpServletRequestWrapper {

    private byte[] body;

    /**
     * Constructs a request object wrapping the given request.
     *
     * @param request The request to wrap
     * @throws IllegalArgumentException if the request is null
     */
    public RepeatableHttpRequestWrapper(HttpServletRequest request) throws IOException {
        super(request);
        this.body = StreamUtils.copyToByteArray(request.getInputStream());
    }


    @Override
    public BufferedReader getReader() throws IOException {
        return new BufferedReader(new InputStreamReader(getInputStream()));
    }


    @Override
    public ServletInputStream getInputStream() throws IOException {

        ByteArrayInputStream bais = new ByteArrayInputStream(this.body);
        return new ServletInputStream() {
            @Override
            public boolean isFinished() {
                return false;
            }

            @Override
            public int available() throws IOException {
                return body.length;
            }

            @Override
            public boolean isReady() {
                return false;
            }

            @Override
            public void setReadListener(ReadListener listener) {

            }

            @Override
            public int read() throws IOException {
                return bais.read();
            }
        };
    }
}
RepeatableFilter
public class RepeatableFilter implements Filter {


    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
            ServletException {
        if (request instanceof HttpServletRequest && StringUtils.startsWithIgnoreCase(request.getContentType(),
                MediaType.APPLICATION_JSON_VALUE)) {
            ServletRequest wrapper = new RepeatableHttpRequestWrapper((HttpServletRequest) request);
            chain.doFilter(wrapper, response);
            return;
        }
        chain.doFilter(request, response);

    }
}

配置

@Configuration
public class MvcConfig {

    @Bean
    public FilterRegistrationBean someFilterRegistration()
    {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new RepeatableFilter());
        registration.addUrlPatterns("/*");
        registration.setName("repeatableFilter");
        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
        return registration;
    }
}

测试

@RestController
public class HelloController {
    @Autowired
    private ObjectMapper objectMapper;

    @PostMapping("user")
    public String hello(@RequestBody User user, HttpServletRequest request) throws JsonProcessingException {
        System.out.println(objectMapper.writeValueAsString(user));
        String body = getBody(request);
        System.out.println("from request body: " + body);
        return "success";
    }


    static public String getBody(HttpServletRequest request) {
        try {
            ServletInputStream in = request.getInputStream();
            String body;
            body = StreamUtils.copyToString(in, Charset.forName("UTF-8"));

            return body;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }

}

结果:

{"name":"aaa","age":23}
from request body: {
  "name": "aaa",
  "age": 23
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值