利用反射在拦截器中获取HttpServletRequest的body数据和HttpServletResponse的返回信息 - ZhangTory's NoteBlog - 张耀誉的笔记博客

利用反射在拦截器中获取HttpServletRequest的body数据和HttpServletResponse的返回信息

记得以前有个需求,在Interceptor中需要通过HttpServletRequest把Post的request body数据提取出来,如果简单的通过Reader是可以读出来,但是在拦截器中只能读一次,之后传到controller的request body为空,会造成后续的业务异常。
网上的方案是通过HttpServletRequestWrapper进行包装,在Filter对InputStream进行读取,稍微有点麻烦。
那么有没有更简单的方法呢?

从HttpServletResponse获取返回信息

首先可以看一下如何通过实现一个HttpServletRequestWrapper包装类来读取request body数据:拦截器获取HttpServletRequest里body数据

而昨晚碰巧看到了一个博客:Spring MVC 拦截器实现日志监控,他需要从HttpServletResponse中获取返回信息,正如同从HttpServletRequest拿到request body数据一样,从HttpServletResponse拿到返回信息也非常麻烦,于是博主使用反射从HttpServletResponse中获取到了返回信息

我觉得思路非常棒,所以我也跟着尝试了一下,可能由于SpringBoot版本有更新,我和原博主有些区别。

resp1.jpg

最终的实现代码:

private String getResponse(HttpServletResponse response) throws IOException, NoSuchFieldException, IllegalAccessException {
    String result = "";
    CoyoteOutputStream os = (CoyoteOutputStream) response.getOutputStream();
    Class<CoyoteOutputStream> cos = CoyoteOutputStream.class;
    Field fs = cos.getDeclaredField("ob");
    if (fs.getType() == OutputBuffer.class) {
        fs.setAccessible(true);
        OutputBuffer ob = (OutputBuffer) fs.get(os);
        Class<OutputBuffer> cc = OutputBuffer.class;
        Field ff = cc.getDeclaredField("bb");
        if (ff.getType() == ByteBuffer.class) {
            ff.setAccessible(true);
            ByteBuffer bc = (ByteBuffer) ff.get(ob);
            result = new String(bc.array(), StandardCharsets.UTF_8);
        }
    }
    return result;
}

从HttpServletRequest获取request body数据

那么,同理我们是否可以获取到HttpServletRequest中request body中的数据呢?

resp2.jpg

看上去是可行的,于是开始写代码实现:

private String getRequest(HttpServletRequest request) throws IOException, NoSuchFieldException, IllegalAccessException {
    String result = "";
    CoyoteInputStream is = (CoyoteInputStream) request.getInputStream();
    Class<CoyoteInputStream> cis = CoyoteInputStream.class;
    Field fs = cis.getDeclaredField("ib");
    if (fs.getType() == InputBuffer.class) {
        fs.setAccessible(true);
        InputBuffer ib = (InputBuffer) fs.get(is);
        Class<InputBuffer> cc = InputBuffer.class;
        Field ff = cc.getDeclaredField("bb");
        if (ff.getType() == ByteBuffer.class) {
            ff.setAccessible(true);
            ByteBuffer bc = (ByteBuffer) ff.get(ib);
            result = new String(bc.array(), StandardCharsets.UTF_8);
        }
    }
    return result;
}

运行测试结果:
resp3.jpg
从结果我们知道了确实可以通过反射,从HttpServletRequest中读取request body数据,并且不会影响到后续的业务。只不过这里读取的是标准的HTTP POST请求格式,需要我们手动从中提取reqeust body数据。

添加新评论

电子邮件地址不会被公开,评论内容可能需要管理员审核后显示。