filter的基本功能大家都是清楚的,本节不赘述,本文主要讲述filter 是否可修改response及如何修改response
通常我们理解tomcat的调用流程是
clinet -> filter -> service
|
clinet <- filter < - -
实际的处理流程是
clinet -> filter -> service
|
filter < - -
clinet <- - - -
用postman测试就会发现,在filter resp时sleep的话,还没sleep结束,已经收到响应
tomcat会在servlet中write tcp报文 之后继续执行filter
如果我们想在filter中修改reponse报文,怎么办呢
如果直接使用response.getWriter().write()方法会报错getOutputStream() has already been called for this response
解决方案是可以封装新的response对象,在调用filterChain.doFilter(servletRequest, servletResponse);
时传入,具体如下
public class ModifyResponseBodyWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream bos;
public ModifyResponseBodyWrapper(HttpServletResponse response) {
super(response);
this.bos = new ByteArrayOutputStream();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new ServletOutputStream() {
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {
}
@Override
public void write(int b) throws IOException {
bos.write(b);
}
@Override
public void write(byte[] b) throws IOException {
bos.write(b);
}
};
}
@Override
public PrintWriter getWriter() throws IOException {
return new PrintWriter(new OutputStreamWriter(bos));
}
public String getResponseBody() throws IOException {
ServletOutputStream outputStream = this.getOutputStream();
outputStream.flush();
PrintWriter writer = this.getWriter();
writer.flush();
return bos.toString(this.getCharacterEncoding());
}
}
这样在servlet中,会将write的内容缓存下来,在filter中真实write