首页 > 技术文章 > 过滤器修改response

tutar 原文

  过滤器通过doFilter方法的第二个参数ServletResponse将输出发送给客户,但servletResponse参数没有为过滤器提供servlet或jsp页面的访问;执行doFilter方法时,servlet或jsp还没修改,当调用FilterChain的doFilter方法时,修改相应似乎为时已晚,以为数据已经发送给客户端,怎么办呢?

  解决这个问题的办法是创建一个像HttpServletResponse的缓冲区,当servlet或jsp调用response.getWiter或者response.getOutputStream并发送输出时,输出实际上没有被发送到客户端,而是放到了该缓冲区中,这样filter就可以在发送到客户端前检查货修改这个输出。大概过程如下

具体代码如下:

1、实现HttpServletResponseWrapper

public class StringWrapper extends HttpServletResponseWrapper {
  private StringWriter stringWriter;//缓存区

  public StringWrapper(HttpServletResponse response) {
    super(response);
    stringWriter = new StringWriter();
  }
  /** 当servlet或jsp请求Writer时,给它们一个被封装过的writer,
   *  其会往缓冲区中写数据
   */
  public PrintWriter getWriter() {
    return(new PrintWriter(stringWriter));
  }
  /** 同样,当 调用 getOutputStream,
    * 返回一个模拟的output stream
    */
  public ServletOutputStream getOutputStream() {
    return(new StringOutputStream(stringWriter));
  }
  /** 返回buffer的字符串表示
   */
  public String toString() {
    return(stringWriter.toString());
  }

2、实现ServletOutputStreanm

public class StringOutputStream extends ServletOutputStream {
  private StringWriter stringWriter;//缓冲区引用
  
  public StringOutputStream(StringWriter stringWriter) {
    this.stringWriter = stringWriter;
  }
  /**重写OutputStream  write方法
   * 这个方法被ServletOutputStream调用而ServletOutputStream extends OutputStream
   */
  public void write(int c) {
    stringWriter.write(c);
  }
}

  看一下ServletOutputStream类print方法

 public void print(String s)
    throws IOException
  {
    if (s == null) s = "null";
    int len = s.length();
    for (int i = 0; i < len; i++) {
      char c = s.charAt(i);

      if ((c & 0xFF00) != 0) {
        String errMsg = lStrings.getString("err.not_iso8859_1");
        Object[] errArgs = new Object[1];
        errArgs[0] = new Character(c);
        errMsg = MessageFormat.format(errMsg, errArgs);
        throw new CharConversionException(errMsg);
      }
      write(c);//在这里被调用
    }
  }
View Code

该类中其他所有输出String信息的方法都调用了该方法  

疑问:当调用FilterChain 的doFilter方法时,怎么说就晚了呢?

  response是一个引用,当调用filterChain doFilter(或者是servlet jsp,没有其他过滤器的话)后,响应就通过这个引用写到端口上去了,所以说为时已晚

推荐阅读