JakartaEE 圧縮フィルタ(Gzip)の仕組みと実装例を完全解説!初心者でもわかるサーブレット高速化
生徒
「先生、Webページを高速化する方法ってありますか?最近アプリが重い気がして…」
先生
「あるよ。JakartaEEではフィルタを使ってレスポンスをGzipで圧縮することで、データ転送を軽くして表示速度を改善できるんだ。」
生徒
「Gzipってブラウザでも対応してるんですか?」
先生
「もちろん。ほとんどのモダンブラウザはGzip圧縮をサポートしているから、サーバー側で圧縮フィルタを作れば簡単に導入できるんだよ。」
1. Gzip圧縮フィルタとは
Gzip圧縮フィルタは、JakartaEEのサーブレットフィルタ機能を活用して、HTTPレスポンスをクライアントに返す前に圧縮する仕組みです。圧縮することでネットワーク帯域の消費を減らし、ページ表示速度を向上させることができます。特にテキストベースのHTMLやCSS、JavaScriptのようなリソースでは効果が高く、Webアプリケーションのパフォーマンス最適化に欠かせない技術です。
2. Gzipフィルタの仕組み
ブラウザがサーバーにリクエストを送るとき、Accept-Encodingヘッダーにgzipが含まれていれば、サーバー側でレスポンスを圧縮して返すことができます。JakartaEEのフィルタではレスポンスストリームを書き換えることで、Gzip圧縮済みのレスポンスをクライアントに返す仕組みを実現します。
3. Gzip圧縮フィルタの実装例
以下はJakartaEEでGzip圧縮フィルタを作成するシンプルなサンプルコードです。
@WebFilter("/*")
public class GzipFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String acceptEncoding = httpRequest.getHeader("Accept-Encoding");
if (acceptEncoding != null && acceptEncoding.contains("gzip")) {
GzipResponseWrapper gzipResponse = new GzipResponseWrapper(httpResponse);
chain.doFilter(request, gzipResponse);
gzipResponse.finishResponse();
} else {
chain.doFilter(request, response);
}
}
}
このフィルタは、ブラウザがGzipを受け入れる場合にのみレスポンスを圧縮して返します。
4. レスポンスラッパークラスの実装
Gzip圧縮を行うためには、レスポンスのOutputStreamをラップするクラスを作成します。
public class GzipResponseWrapper extends HttpServletResponseWrapper {
private GZIPServletOutputStream gzipOutputStream;
private PrintWriter printWriter;
public GzipResponseWrapper(HttpServletResponse response) throws IOException {
super(response);
}
@Override
public ServletOutputStream getOutputStream() throws IOException {
if (gzipOutputStream == null) {
gzipOutputStream = new GZIPServletOutputStream(getResponse().getOutputStream());
}
return gzipOutputStream;
}
@Override
public PrintWriter getWriter() throws IOException {
if (printWriter == null) {
printWriter = new PrintWriter(new OutputStreamWriter(getOutputStream(), getCharacterEncoding()));
}
return printWriter;
}
public void finishResponse() throws IOException {
if (printWriter != null) {
printWriter.close();
}
if (gzipOutputStream != null) {
gzipOutputStream.close();
}
}
}
5. GZIPServletOutputStreamの実装
実際にレスポンスをGzipで圧縮するServletOutputStreamの実装例です。
public class GZIPServletOutputStream extends ServletOutputStream {
private GZIPOutputStream gzipOutputStream;
public GZIPServletOutputStream(OutputStream output) throws IOException {
this.gzipOutputStream = new GZIPOutputStream(output);
}
@Override
public void write(int b) throws IOException {
gzipOutputStream.write(b);
}
@Override
public void flush() throws IOException {
gzipOutputStream.flush();
}
@Override
public void close() throws IOException {
gzipOutputStream.close();
}
@Override
public boolean isReady() {
return true;
}
@Override
public void setWriteListener(WriteListener writeListener) {}
}
6. 実行結果の確認
実際にこのフィルタを導入すると、ブラウザの開発者ツールやcurlコマンドでレスポンスヘッダーを確認できます。
Content-Encoding: gzip
このヘッダーが返っていれば、レスポンスが圧縮されていることを意味します。
7. Gzip圧縮フィルタを使うメリット
- レスポンスサイズを大幅に削減できる
- ページ表示速度が向上し、ユーザー体験が改善する
- ネットワーク帯域の節約につながる
- JakartaEEのフィルタで簡単に導入可能
8. 導入時の注意点
すべてのレスポンスをGzip圧縮するとCPU負荷が増える可能性があるため、画像やPDFのようにすでに圧縮されているデータには適用しないようにする工夫が必要です。また、HTTPヘッダーの設定やクライアントの互換性も考慮して導入しましょう。