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

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

在使用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        tr
HttpServletRequestWrapper 是一个用来增强 HttpServletRequest 的类,它实现了 HttpServletRequest 接口,并且可以通过继承它来对 HttpServletRequest 进行增强。 下面是一个使用 HttpServletRequestWrapper 的示例代码: ```java public class CustomHttpServletRequestWrapper extends HttpServletRequestWrapper { private Map<String, String[]> customParams; public CustomHttpServletRequestWrapper(HttpServletRequest request) { super(request); customParams = new HashMap<>(); } public void addParameter(String name, String value) { String[] values = customParams.get(name); if (values == null) { values = new String[] { value }; } else { values = Arrays.copyOf(values, values.length + 1); values[values.length - 1] = value; } customParams.put(name, values); } @Override public String getParameter(String name) { String[] values = customParams.get(name); if (values != null && values.length > 0) { return values[0]; } return super.getParameter(name); } @Override public String[] getParameterValues(String name) { String[] values = customParams.get(name); if (values != null && values.length > 0) { return values; } return super.getParameterValues(name); } } ``` 这个类继承了 HttpServletRequestWrapper,并且实现了添加参数和获取参数的方法。在 addParameter 方法中,我们将自定义的参数存储到 customParams 中;在 getParameter 和 getParameterValues 方法中,我们首先从 customParams 中获取参数值,如果没有则调用父类的方法获取使用这个类可以很方便地对 HttpServletRequest 进行增强,比如在参数中添加一些自定义参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值