HttpServletRequest und HttpServletResponse und die Header

Sendet der HTTP-Client eine Anfrage an den Server, so sendet er gleichzeitig einige Informationen über sich mit. Sie nennen sich Header und bezeichnen Schlüssel-Werte-Paare, die durch einen Doppelpunkt getrennt sind. Ein Webbrowser kann zum Beispiel Folgendes formulieren:

GET /seminare/index.html HTTP/1.0
Accept-Language: de

Der Browser sendet hier den Header Accept-Language mit dem Wert de. So kann der Server unter Auswertung dieser Parameter optimal reagieren, zum Beispiel bei der Präferenz der Sprache eine lokalisierte Webseite liefern. Um an die Header zu gelangen, müssen wir das HttpServletRequest-Objekt lesen und die Header erfragen.

Header auslesen

Zum Lesen der Header in einem Servlet bieten sich zwei Lösungen an: Wenn wir einen speziellen Header erfragen wollen, dann holen wir mit getHeader() auf dem HttpServletRequest den passenden Wert zum Schlüssel. Sind wir an allen Schlüsseln interessiert, dann besorgt uns getHeaderNames() eine Enumeration. Die können wir dann durchlaufen und die Werte wiederum mit getHeader() auslesen. Falls ein Schlüssel nicht existiert, liefert die Methode null. Ähnlich wie bei getParameter() können hier auch mehrere Einträge existieren, die mit getHeaders() abgerufen werden können.

<%
java.util.Enumeration headerNames = request.getHeaderNames();
while ( headerNames.hasMoreElements() )
{
String headerNameKey = (String) headerNames.nextElement();
String headerNameValue = request.getHeader( headerNameKey );
%>
<%= headerNameKey %>: <%= headerNameValue %>
<p>
<%
}
%>

Das Servlet erzeugt für eine Anfrage etwa folgende Ausgabe:

accept: image/gif, image/x-xbitmap, image/jpeg, image/pjpeg, application/vnd.ms-excel, application/vnd.ms-powerpoint, application/msword, */*
accept-language: de
accept-encoding: gzip, deflate
user-agent: Mozilla/4.0 (compatible; MSIE 9.0; Windows NT 5.0)
host: localhost:8080
connection: Keep-Alive
cookie: JSESSIONID=EB9D8DFAB0D0AA1B38D292507983B6B1

Der Anfragetyp (GET, POST und so weiter) wird hier ebenso wenig angezeigt wie der Remote-Host. Dieser findet sich nicht im Header und muss mit anderen Funktionen erfragt werden.

Hilfsfunktion im Umgang mit Headern

Wieder gibt es für oft benutzte Header Abkürzungen.

  • getMethod() liefert eine Zeichenkette wie GET oder POST.
  • Die Methode getRequestURI() liefert die URI der Anfrageseite.
  • getProtocol() liefert das Protokoll von der Statuszeile, also heutzutage entweder HTTP/1.0 oder HTTP/1.1.
  • getCookies() liefert den Inhalt des Cookie-Headers (dazu später mehr).
  • getAuthType() und getRemoteUser() zerteilen die Information im Authorization-Feld in Komponenten.
  • getDateHeader() und getIntHeader() sind wieder Hilfsmethoden.

Übersicht der Browser-Header

Hier eine Übersicht über die üblichen Header, von denen wir manche schon aus dem Beispiel und auch vom Server kennen:

  • Accept. Der vom Browser bevorzugte MIME-Typ.
  • Accept-Charset. Der vom Browser bevorzugte Zeichensatz.
  • Accept-Encoding. Die Kodierung, die der Browser verarbeiten kann, wie etwa gzip oder compress. Unser Servlet-Programm sollte vor dem Komprimieren testen, ob der Browser überhaupt komprimierte Dateien verarbeiten kann.
  • Accept-Language. Die Sprache, die der Browser bevorzugt anzeigt. Mehr als ein Eintrag, wenn der Browser mehr als eine Sprache spricht.
  • Authorization. Information über Autorisierung, die normalerweise eine Antwort auf die WWW-Authenticate-Anfrage des Servers ist.
  • Connection. Informiert, ob persistente Verbindungen genutzt werden. Persistente Übertragungen übermitteln in einer TCP/IP-Verbindung mehrere Dateien, etwa eine HTML-Datei und mehrere Grafiken. Wenn der Wert von Connection »Keep-Alive« heißt, dann lassen sich mit einer Netzwerkverbindung mehrere Seitenteile übermitteln. Wenn die Request-Zeile die http-Version 1.1 anzeigt, sind Keep-Alive-Verbindungen Standard. Unsere Aufgabe bei diesen Verbindungen ist es, den Header ContentLength in die Antwort zu setzen. Server-abhängig wird hier teilweise schon automatisch in einen Puffer geschrieben und die Größe gesetzt. Dies muss aber nicht so sein, daher bietet es sich an, die Informationen in einen ByteArrayOutputStream zu schreiben, um später die Länge und den Inhalt abzufragen.
  • Content-Length. Die Länge des Bytestroms. Hier zählt der Browser die Bytes und informiert den Server, wie viele Daten noch kommen.
  • Cookie. Cookie-Information, die der Browser automatisch mitschickt.
  • From. Ein optionaler Header, der oft von Webrobotern gesetzt wird. Bei Browsern nicht üblich.
  • Host. Rechnername und Host, wie in der Original-URL angegeben.
  • If-Modified-Since. Liefert ein neues Server-Dokument, wenn die im Header angegebene Zeit auf ein neueres Dokument verweist. Ist das Browser-Dokument aktueller, gibt der Server den Antwortcode 304 mit der Nachricht »Not Modified« zurück.
  • Pragma. Gibt Informationen über das automatische Neuladen der Seiten. Der Wert no-cache zeigt an, dass der Server immer eine neue Seite liefern soll, auch wenn der Proxy eine Kopie hält.
  • Referer. Die URL mit dem Verweis, der auf die aktuelle Seite gezeigt hat.
  • User-Agent. Der Browsertyp. Praktisch, wenn unser Servlet JavaScript-Code einbettet, der vom Browser abhängig ist.
  • UA-Pixels, UA-Color, UA-OS, UA-CPU. Von Microsoft eingeführte proprietäre Header für den Internet Explorer, die Bildschirmgröße, Farbtiefe, Betriebssystem und CPU-Typ anzeigen.

Header, die der Server setzt

Bisher kennen wir von der Klasse HttpServletResponse die Methode setHeader() für beliebige Header.

Beispiel: Setze den Header pragma, damit vom Browser keine Daten im Cache gehalten werden:

response.setHeader( "pragma", "no-cache" );

Mit dieser Aufforderung soll der Browser die Seite jedes Mal neu laden. Das ist bei dynamischen Seiten besonders wichtig, da sie bei jedem Aufruf neu generiert werden und sich Werte ändern können, wie es zum Beispiel bei Warenkorbsystemen der Fall ist. Da wir uns als Applikationsentwickler nicht immer mit dem Namen der Header herumärgern wollen, bietet die Bibliothek einige Spezialfunktionen an.

Beispiel: Für den Header Content-Type gibt es die spezielle Methode setContentType():

response.setHeader( "Content-Type", "text/html");
response.setContentType( "text/html" );

Daneben gibt es setContentLength(), die den Header Content-Length setzt. Diese Länge muss nicht gesetzt werden und wird automatisch berechnet. Falsche Längen könnten zu Ausnahmesituationen führen. Der Gebrauch ist jedoch nützlich, wenn vorher die gesamte Webseite in einem StringBuffer sb gesammelt und in einem Rutsch übertragen wird. Dann können wir setContentLength(sb.length()) aufrufen.

Um einen Datums-Header zu setzen, existiert setDateHeader(String, long). Das Argument ist eine beliebige Zeichenkette, die mit einem Datumswert verbunden wird. Das long gibt die Millisekunden seit dem 1.1.1970 an. Die erzeugte Ausgabe schreibt einen UTC-String. Eine weitere Hilfsfunktion ist setIntHeader(), die Zahlenwerte mit Schlüsseln in den Header schreibt. Hier übernimmt die Methode die Konvertierung von String in eine Ganzzahl.

Neben diesen setXXX()-Methoden, die möglicherweise gesetzte Header überschreiben, lässt sich mit containsHeader(String) abfragen, ob Wertepaare schon gesetzt sind. Neben den setXXX()-Methoden gibt es auch entsprechende addXXX()-Methoden, die die Werte nicht überschreiben, sondern hinzufügen. Für Cookies existiert eine zusätzliche Methode namens addCookie(), die einen Cookie im Header setzt.

Über Christian Ullenboom

Ich bin Christian Ullenboom und Autor der Bücher ›Java ist auch eine Insel. Einführung, Ausbildung, Praxis‹ und ›Java SE 8 Standard-Bibliothek. Das Handbuch für Java-Entwickler‹. Seit 1997 berate ich Unternehmen im Einsatz von Java. Sun ernannte mich 2005 zum ›Java-Champion‹.

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.