利用Filter和HttpServletResponseWrapper如何拦截response数据

新手小白一枚,记录一下学习filter过程中的知识。

都知道HttpServletResponseWrapper是一个用来创建虚拟response的类,通过这个类可以截获response的内容,是我们可以对其进行一些处理,但是具体是怎么从response获得数据,下面是我自己的一点理解。如有错误,欢迎指正。

首先,要想对request、response进行过滤或拦截,需要使用实现Filter这个接口的类,然后在自身的doFilter方法中中进行一些过滤之类的处理,然后再调用一个filterchain.doFilter方法把request和response传递下去。
那么,如果我们想要拦截response返回的数据,就不能直接把原始的response传入doFilter方法,因为这样数据就会直接socket,所以我们需要利用HttpServletResponseWrapper来创建一个虚拟的response来确保获得输出的数据。

public class CacheFilter implements Filter{}
class CachedHttpServletResponse extends HttpServletResponseWrapper{}

通过上面代码的形式我们可以编写自己的Filter和Wrapper,然后在Wrapper类里面覆写我们需要的方法,大致如下所示

public PrintWriter getWriter() throws IOException {
        if (open) {
            throw new IllegalStateException("Cannot re-open writer!");
        }
        open = true;
        return new PrintWriter(output, false, StandardCharsets.UTF_8);
    }

    // 获取OutputStream:
    public ServletOutputStream getOutputStream() throws IOException {
        if (open) {
            throw new IllegalStateException("Cannot re-open output stream!");
        }
        open = true;
        return new ServletOutputStream() {
            public boolean isReady() {
                return true;
            }

            public void setWriteListener(WriteListener listener) {
            }

            // 实际写入ByteArrayOutputStream:
            public void write(int b) throws IOException {
                output.write(b);
            }
        };
    }
    public byte[] getContent() {
        return output.toByteArray();
    }

在我们想要截获response的数据时,可以在Filter的doFilter方法中写下这样的代码

CachedHttpServletResponse wrapper = new CachedHttpServletResponse(resp);
            chain.doFilter(request, wrapper);

这样filterchain就会把wrapper这个虚拟的response传递给下一个目标,而这个目标就是处理request的一个servlet实例,假如是一个get请求,那么doGet方法传入参数就是request和wrapper,此方法从后端(比如数据库)获取数据后就会调用response的writer写入数据,但这里传入的是wrapper,所以就会调用我们覆写的writer或outputstream,把数据写到我们的output,通过这样我们就获得了数据,可以对其进行处理。处理完之后再将其交给原始的response调用writer写入,返回给前端。

另外,如果filter实现了缓存,那么我们就可以将从后方获取的数据缓存起来,等到再次遇到同样的请求时,就不必再去后方获取数据,而是直接将缓存写入response,节省开销,提高效率。

Logo

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。

更多推荐