今回はサーブレットフィルタでGZIP圧縮に対応してみたいと思います。
必要なクラス
圧縮されたHTTPリクエストの解凍と、HTTPレスポンスの圧縮を実現するには、次の5つのクラスが必要です。
- GZIPFilter - Filterを実装します。HTTPヘッダを確認し、圧縮/解凍をするかどうか判断します。
- GZIPRequest - HttpServletRequestWrapperを継承します。GZIPServletInputStreamを返します。
- GZIPServletInputStream - HTTPリクエストを解凍するInputStreamです。
- GZIPResponse - HttpServletResponseWrapperを継承します。GZIPServletOutputStreamを返します。
- GZIPServletOutputStream - HTTPレスポンスを圧縮するOutputStreamです。
プログラム
GZIPFilter.java
package gzip;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class GZIPFilter implements Filter {
@Override
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain)
throws IOException, ServletException
{
if (!(req instanceof HttpServletRequest)
|| !(resp instanceof HttpServletResponse)) {
chain.doFilter(req, resp);
return;
}
HttpServletRequest httpReq = (HttpServletRequest) req;
HttpServletResponse httpResp = (HttpServletResponse) resp;
if (this.decompressRequired(httpReq)) {
httpReq = new GZIPRequest(httpReq);
}
if (this.compressRequired(httpReq)) {
httpResp = new GZIPResponse(httpResp);
}
chain.doFilter(httpReq, httpResp);
}
private boolean decompressRequired(HttpServletRequest request) {
String contentEncoding = request.getHeader("Content-Encoding");
return "gzip".equals(contentEncoding);
}
private boolean compressRequired(HttpServletRequest request) {
String acceptEncoding = request.getHeader("Accept-Encoding");
return "gzip".equals(acceptEncoding);
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
// nothing to do
}
@Override
public void destroy() {
// nothing to do
}
}
GZIPRequest.java
package gzip;
import java.io.IOException;
import javax.servlet.ServletInputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletRequestWrapper;
public class GZIPRequest extends HttpServletRequestWrapper {
public GZIPRequest(HttpServletRequest request) {
super(request);
}
@Override
public ServletInputStream getInputStream() throws IOException {
return new GZIPServletInputStream(super.getInputStream());
}
}
GZIPServletInputStream.java
package gzip;
import java.io.IOException;
import java.util.zip.GZIPInputStream;
import javax.servlet.ServletInputStream;
public class GZIPServletInputStream extends ServletInputStream {
private GZIPInputStream gzipStream;
public GZIPServletInputStream(ServletInputStream stream)
throws IOException
{
this.gzipStream = new GZIPInputStream(stream);
}
@Override
public int read() throws IOException {
return gzipStream.read();
}
@Override
public void close() throws IOException {
gzipStream.close();
}
}
GZIPResponse.java
package gzip;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
public class GZIPResponse extends HttpServletResponseWrapper {
public GZIPResponse(HttpServletResponse response) {
super(response);
super.setHeader("Content-Encoding", "gzip");
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
return new GZIPServletOutputStream(super.getOutputStream());
}
}
GZIPServletOutputStream.java
package gzip;
import java.io.IOException;
import java.util.zip.GZIPOutputStream;
import javax.servlet.ServletOutputStream;
public class GZIPServletOutputStream extends ServletOutputStream {
private final GZIPOutputStream gzipStream;
public GZIPServletOutputStream (ServletOutputStream out)
throws IOException {
this.gzipStream = new GZIPOutputStream(out);
}
@Override
public void write(int b) throws IOException {
this.gzipStream.write(b);
}
@Override
public void close() throws IOException {
this.gzipStream.close();
}
}
EchoServlet.java
package gzip;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class EchoServlet extends HttpServlet {
@Override
public void doPost(HttpServletRequest req, HttpServletResponse resp)
throws IOException, ServletException {
InputStream in = req.getInputStream();
OutputStream out = resp.getOutputStream();
int input = 0;
while (-1 != (input = in.read())) {
out.write(input);
}
out.flush();
}
}
通常であれば、HTTPサーバーで対応するのが妥当でしょう。
あえてサーブレットフィルタで実装するメリットがあるとすれば、warファイルにまとめられるので管理が楽になることでしょうか。
クライアントプログラム(C#)は次回の更新で載せる予定です。
関連
GZIP圧縮に対応したHTTPクライアントを作る
0 件のコメント:
コメントを投稿