[JAVA]利用Filter修改Response

在内存中开辟一个ByteOutputStream,然后将拦截的响应写入byte[],写入完毕后,再将wrapper的byte[]写入真正的response对象

下面的例子是《Spring 2.0核心技术与最佳实践》中的例子:

package net.livebookstore.web.filter;

import java.io.*;

import javax.servlet.*;
import javax.servlet.http.*;

/**
* This class is used for wrapped response for getting cached data.
*
* @author Xuefeng
*/
class CachedResponseWrapper extends HttpServletResponseWrapper {

/**
* Indicate that getOutputStream() or getWriter() is not called yet.
*/
public static final int OUTPUT_NONE = 0;

/**
* Indicate that getWriter() is already called.
*/
public static final int OUTPUT_WRITER = 1;

/**
* Indicate that getOutputStream() is already called.
*/
public static final int OUTPUT_STREAM = 2;

private int outputType = OUTPUT_NONE;

private int status = SC_OK;
private ServletOutputStream output = null;
private PrintWriter writer = null;
private ByteArrayOutputStream buffer = null;

public CachedResponseWrapper(HttpServletResponse resp) throws IOException {
super(resp);
buffer = new ByteArrayOutputStream();
}

public int getStatus() { return status; }

public void setStatus(int status) {
super.setStatus(status);
this.status = status;
}

public void setStatus(int status, String string) {
super.setStatus(status, string);
this.status = status;
}

public void sendError(int status, String string) throws IOException {
super.sendError(status, string);
this.status = status;
}

public void sendError(int status) throws IOException {
super.sendError(status);
this.status = status;
}

public void sendRedirect(String location) throws IOException {
super.sendRedirect(location);
this.status = SC_MOVED_TEMPORARILY;
}

public PrintWriter getWriter() throws IOException {
if(outputType==OUTPUT_STREAM)
throw new IllegalStateException();
else if(outputType==OUTPUT_WRITER)
return writer;
else {
outputType = OUTPUT_WRITER;
writer = new PrintWriter(new OutputStreamWriter(buffer, getCharacterEncoding()));
return writer;
}
}

public ServletOutputStream getOutputStream() throws IOException {
if(outputType==OUTPUT_WRITER)
throw new IllegalStateException();
else if(outputType==OUTPUT_STREAM)
return output;
else {
outputType = OUTPUT_STREAM;
output = new WrappedOutputStream(buffer);
return output;
}
}

public void flushBuffer() throws IOException {
if(outputType==OUTPUT_WRITER)
writer.flush();
if(outputType==OUTPUT_STREAM)
output.flush();
}

public void reset() {
outputType = OUTPUT_NONE;
buffer.reset();
}

/**
* Call this method to get cached response data.
* @return byte array buffer.
* @throws IOException
*/
public byte[] getResponseData() throws IOException {
flushBuffer();
return buffer.toByteArray();
}

/**
* This class is used to wrap a ServletOutputStream and
* store output stream in byte[] buffer.
*/
class WrappedOutputStream extends ServletOutputStream {

private ByteArrayOutputStream buffer;

public WrappedOutputStream(ByteArrayOutputStream buffer) {
this.buffer = buffer;
}

public void write(int b) throws IOException {
buffer.write(b);
}

public byte[] toByteArray() {
return buffer.toByteArray();
}
}

}

在Filter中调用:

public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException
{
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse)response;
CachedResponseWrapper wrapper = new CachedResponseWrapper(httpResponse);
// 写入wrapper:
chain.doFilter(request, wrapper);
// 首先判断status, 只对200状态处理:
if(wrapper.getStatus()==HttpServletResponse.SC_OK) {
// 对响应进行处理,这里是进行GZip压缩:
byte[] data = GZipUtil.gzip(wrapper.getResponseData());
httpResponse.setContentType(wrapper.getContentType());
httpResponse.setContentLength(data.length);
httpResponse.setHeader("Content-Encoding", "gzip");
ServletOutputStream output = response.getOutputStream();
output.write(data);
output.flush();
}
}

需要判断状态,正确设置Content-Length,具体可参考《Spring 2.0核心技术与最佳实践》第十一章12节:利用Filter实现内存缓存和静态文件缓存。


如果给你带来帮助,欢迎微信或支付宝扫一扫,赞一下。