In einer unserer Webapplikationen kann der Benutzer ein Image (GIF,PNG) uploaden welches auf jeder HTML Seite der Applikation angezeigt wird. Dieses Bild wird in der Datenbank abgelegt und wenn benötigt via Servlet zum Client gesendet.
Eine erste Implementation dieses Servlets sah folgendermassen aus:
public class LogoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
byte[] imageDate = .... //Bild holen. Datenbankzugriff
if (imageDate != null) {
response.setContentType(...);
OutputStream out = response.getOutputStream();
out.write(imageDate);
out.close();
}
}
}
Die web.xml Datei enthält folgenden Eintrag.
<servlet>
<servlet-name>logo</servlet-name>
<servlet-class>LogoServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>logo</servlet-name>
<url-pattern>/logo.gif</url-pattern>
</servlet-mapping>
Da dieses Bild auf jeder Seite eingebunden ist, wird nun jedesmal wenn der Benutzer eine neue Seite aufruft auch jedesmal das ganze Image zum Client gesendet. Da sich dieses Bild praktisch nie ändert könnte der Browser das Bild cachen und der Server müsste es nicht jedesmal senden.
Zu diesem Zweck wurde in HTTP/1.1 der ETag (Entity Tag) eingeführt. Dazu sendet der Server für statische und dynamische Inhalte (welche sich selten ändern) im Header der Response einen ETag mit. Der ETag kann auf verschiedene Arten berechnet werden. Eine Methode ist es das Änderungsdatum zu verwenden oder man berechnet zum Beispiel mit MD5 einen Hash von der Datei.

Der Browser kann nun mit Hilfe dieses ETag die erhaltene Information im Cache ablegen. Wenn er die Information erneut benötigt sendet der Browser den ETag im Request (If-None-Match) mit und der Server entscheidet dann aufgrund des ETag ob sich die Daten in der Zwischenzeit verändert haben. Wenn sich nichts geändert hat sendet der Server nur eine Response mit dem Code 304 Not Modified und einem leeren Body zurück.

Statische Inhalte (Images, usw.) die sich in einer Webapplikation befinden werden vom Container (z.B. Tomcat) nach diesem Prinzip ausgeliefert. Dynamische Inhalte wie unser Image das der Benutzer uploaden kann müssen dagegen selber behandelt werden. Folgendes Servlet zeigt wie ein ETag Handling aussehen könnte.
public class LogoServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String etag = ... //ETag holen. Kann zum Beispiel im Speicher abgelegt sein.
if (etag != null) {
String previousToken = request.getHeader("If-None-Match");
String token = '"' + etag + '"';
//ETag bei jeder Antwort mitsenden
response.setHeader("ETag", token);
if (previousToken != null && previousToken.equals(token)) {
response.sendError(HttpServletResponse.SC_NOT_MODIFIED);
} else {
response.setContentType(...);
byte[] imageDate = .... //Bild holen. Datenbankzugriff
OutputStream out = response.getOutputStream();
out.write(imageDate);
out.close();
}
}
}
}
Weitere Links zum Thema
http://en.wikipedia.org/wiki/HTTP_ETag
http://caucho.com/resin/doc/proxy-cache.xtp
http://www.infoq.com/articles/etags
http://www.oreillynet.com/onjava/blog/2004/07/optimizing_http_downloads_in_j.html