Gzip Servlet Filter in Spring MVC
在这篇博客中,我将解释如何在Spring Web应用程序中使用GZip servlet过滤器来加速页面加载。GZip servlet过滤器用于压缩JSP数据(html,JS,CSS)并发送到浏览器,然后浏览器将自动解压缩它。 这加快了页面加载比较没有压缩数据发送到浏览器。
How it works
在呈现jsp页面之前,过滤器将通过名为ACCEPT_ENCODING的标头获取浏览器属性。 因此,如果浏览器支持GZip编码格式,filter会将servletResponse封装到我们的自定义封装器中,并将封装后的响应发送给浏览器,然后浏览器将对其进行解压缩。 如果浏览器不支持Gzip编码格式,那么我们的过滤器将发送未包装的响应。
每当请求发送到服务器时,GZip servlet过滤器会封装HttpServletResponse并覆盖ServletResponse的getWritter()和getOutputStream()方法,以便在响应中写入压缩的字符串。
Here is the Code
GZIPFilter.java
public class GZIPFilter implements Filter {
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String acceptEncoding = httpRequest.getHeader(HttpHeaders.ACCEPT_ENCODING);
if (acceptEncoding != null) {
System.out.println("Processing GZIPFilter");
//searching for 'gzip' in ACCEPT_ENCODING header
if (acceptEncoding.indexOf("gzip") >= 0) {
GZIPResponseWrapper gzipResponse = new GZIPResponseWrapper(httpResponse);
chain.doFilter(request, gzipResponse);
gzipResponse.finish();
return;
}
}
chain.doFilter(request, response);
}
}
现在这里是ServletResponseWrapper的代码,它覆盖ServletResponse的方法来编写压缩的响应。
GZIPResponseWrapper.java
public class GZIPResponseWrapper extends HttpServletResponseWrapper {
private GZIPResponseStream gzipStream;
private ServletOutputStream outputStream;
private PrintWriter printWriter;
public GZIPResponseWrapper(HttpServletResponse response) {
super(response);
response.addHeader(HttpHeaders.CONTENT_ENCODING, "gzip");
}
public void finish() throws IOException {
if (printWriter != null) {
printWriter.close();
}
if (outputStream != null) {
outputStream.close();
}
if (gzipStream != null) {
gzipStream.close();
}
}
@Override
public void flushBuffer() throws IOException {
if (printWriter != null) {
printWriter.flush();
}
if (outputStream != null) {
outputStream.flush();
}
super.flushBuffer();
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (printWriter != null) {
throw new IllegalStateException("printWriter already defined");
}
if (outputStream == null) {
initGzip();
outputStream = gzipStream;
}
return outputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
if (outputStream != null) {
throw new IllegalStateException("printWriter already defined");
}
if (printWriter == null) {
initGzip();
printWriter = new PrintWriter(new OutputStreamWriter(gzipStream, getResponse().getCharacterEncoding()));
}
System.out.println("GZIPFilter is Working fine!!!!!");
return printWriter;
}
/* Creates a new output stream for writing compressed data in
* the GZIP file format. */
private void initGzip() throws IOException {
gzipStream = new GZIPResponseStream(getResponse().getOutputStream());
}
}
GZIPResponseStream.java
public class GZIPResponseStream extends ServletOutputStream {
GZIPOutputStream gzipStream;
final AtomicBoolean open = new AtomicBoolean(true);
OutputStream output;
public GZIPResponseStream(OutputStream output) throws IOException {
this.output = output;
gzipStream = new GZIPOutputStream(output);
}
@Override
public void close() throws IOException {
if (open.compareAndSet(true, false)) {
gzipStream.close();
}
}
@Override
public void flush() throws IOException {
gzipStream.flush();
}
@Override
public void write(byte b[]) throws IOException {
write(b, 0, b.length);
}
@Override
public void write(byte b[], int off, int len) throws IOException {
if (!open.get()) {
throw new IOException("Stream closed!");
}
gzipStream.write(b, off, len);
}
@Override
public void write(int b) throws IOException {
if (!open.get()) {
throw new IOException("Stream closed!");
}
gzipStream.write(b);
}
}