使用HttpServletRequestWrapper解决无法多次获取request Body的问题

在AOP编程中,多次获取HttpServletRequest的body会导致异常,因为默认的HttpServletRequest只允许读取一次。通过继承HttpServletRequestWrapper并创建RequestWrapperFilter,可以在过滤器中将原始HttpServletRequest替换为HttpServletRequestWrapper,从而实现多次读取。RequestWrapper覆盖了getInputStream和getReader方法,使得在ApiAuthAspect切面中可以再次读取请求消息体进行签名校验。

在使用AOP编程的时候,经常碰到需要多次获取整个请求的body的情况。例如:典型场景下我们要在AOP切面中做日志记录或权限校验,此时需要调用request.getInputStream获取输入流,从而读取整个请求的消息体。但是这通常会触发一个异常:java.lang.IllegalStateException: getInputStream() can't be called after getReader()

出现这个问题的原因是默认的HttpServletRequest对象中的getInputStream,getReader函数式只允许调用一次。在一次请求中,除了我们在切面中调用getInputStream之外,Spring MVC框架在进行参数转换的时候还需要调用getInputStream方法读取整个请求的消息体,然后转回为请求参数,这违背了只调用一次的原则,从而触发了以异常,

为了解决这个问题,我们可以引入HttpServletRequestWrapper这个对象。这个类封装了HttpServletRequest的行为,我们可以继承这个类,从而使用一个新类模拟原始HttpServletRequest的行为。然后使用过滤器(filter)将原始的HttpServletRequest对象替换为HttpServletRequestWrapper对象。

最近在项目中有需求为API请求增加参数签名校验,使用了AOP切面功能,因此碰到了上面的问题:参数校验切面中需要在读取整个请求报文,然后对报文进行hmac算法从而计算签名值。下面说一下具体的解决办法,以代码为主。

1. 相关代码

1.1 RequestWrapper

RequestWrapper继承了HttpServletRequestWrapper,初始化的时候读取Request的整个请求体。然后重载了getInputStreamgetReader方法,这两个方法会从类变量body中读取内容。

 1public class RequestWrapper extends HttpServletRequestWrapper {
 2    private final String body;
 3
 4    public RequestWrapper(HttpServletRequest request) throws IOException
 5    {
 6        //So that other request method behave just like before
 7        super(request);
 8
 9        StringBuilder stringBuilder = new StringBuilder();
10        BufferedReader bufferedReader = null;
11        try {
12            InputStream inputStream = request.getInputStream();
13     
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值