Webserver/Alternative Dokumentinhalte

Aus SELFHTML-Wiki
Wechseln zu: Navigation, Suche

Informationen zum Autor

Name:
Michael Schröpl
E-Mail:
Homepage:

Hinweis

Dieser Artikel ist eine Textübertragung aus dem aktuell.de.selfHTML-Bereich. Seine Inhalte sind möglicherweise veraltet.
  • zuerst erschienen: 1.09.1999,
  • letzte Aktualisierung: 29.06.2001
Beschreibung der Möglichkeit, über die Apache-Konfiguration und HTTP-Header-Information z.B. browser-abhängige Sprachvarianten von Webseiten zu präsentieren

Normalerweise ist ein URL (uniform resource locator) die Adresse eines eindeutigen Objektes im World Wide Web. Tatsächlich aber greifen Benutzer unter Verwendung verschiedener, vor allem verschieden mächtiger bzw. konfigurierter Programme (Browser etc.), auf diese Dateien zu und stellen den Inhalt somit unterschiedlich dar.

Der Versuch, eine Web-Seite, eine Graphik etc. so zu gestalten, dass sie für jeden Browser funktioniert und gut aussieht, führt zu entsprechenden Anstrengungen, die Seiten selbst 'intelligent' zu gestalten (etwa über DHTML), was selbst wiederum die Existenz und Aktivierung weiterer Fähigkeiten des Browsers (JavaScript etc.) zur Interpretation dieser Intelligenz erfordert und das Problem letztlich nur verlagert.

Wäre es nicht schöner, wenn der Browser (nicht der Anwender!) dem Webserver mitteilen könnte, was er kann und was er am liebsten mag? Genau das soll das Thema des vorliegenden Artikels sein: Ein Verfahren, nach dem Browser und Webserver den tatsächlichen Inhalt einer über eine eindeutige URL bezeichneten Datei untereinander aushandeln.

Was man dafür nicht braucht, das ist ein nagelneuer Browser - ganz im Gegenteil, es soll ja mit jedem Browser funktionieren! Ältere Browser sind bezüglich ihrer Wünsche höchstens etwas schüchterner; darauf sollte der Verhandlungspartner eingehen. Der Webserver ist es nämlich, der die Verhandlung leiten und auf entsprechenden Wünsche seiner 'digitalen Besucher' angemessen reagieren muss.

HTTP-Header[Bearbeiten]

Ein Browser empfängt von einem Webserver nicht nur den Inhalt einer Datei, sondern gleichzeitig auch weitere Informationen, anhand welcher er die Verarbeitung des Dateiinhalts vorzunehmen hat. Zusammen mit einem HTML-Dokument sollte der Webserver dem Browser beispielsweise einen HTTP-Header mit dem Inhalt Content-type: text/html senden, um diesem klar zu machen, dass er ein Dokument mit dem MIME-Typ HTML darzustellen hat (egal, wie die URL dazu heißt - die Endung des Namens ist nicht immer aussagekräftig genug).

Der Browser muss also die 'Sprache' HTTP (das HyperText Transfer Protocol) verstehen, um zu erkennen, was er tun soll. In derselben Sprache kann er selbst dem Webserver aber auch mitteilen,

  • welche MIME-Typen er versteht bzw. mit welcher Qualität darstellen kann,
  • welche Landessprachen er bevorzugt

und anderes mehr. Einiges davon ist abhängig von den Fähigkeiten des Browsers, anderes von seiner Konfiguration, in welcher der Anwender z. B. eine Prioritätenliste für ihm genehme Landessprachen definieren kann.

Was genau hierbei alles möglich ist, das würde den Rahmen des vorliegenden Artikels sprengen. Dieser wird sich daher auf einen Spezialfall konzentrieren: Wir wollen ein Dokument in mehreren verschiedenen Landessprachen anbieten und den Browser entscheiden lassen, in welcher Sprache er das Dokument bevorzugt erhalten möchte. Da dieser Spezialfall im Rahmen der Internationalisierung von Web Sites relativ häufig auftritt, gibt es neben der allgemeinen Methode zur Verhandlung des Dateiinhalts noch eine speziellere, die bei eingeschränkter Funktionalität leichter konfigurierbar ist; da beide Methoden aufeinander aufbauen, wird dieser Artikel sich mit beiden befassen müssen.

Meine eigenen Erfahrungen basieren auf der Verwendung des Apache-Webservers, welche das hier beschriebene Verfahren mindestens seit der Version 1.1 unter der Bezeichnung server-driven content negotiation realisiert. Da das Verfahren auf dem allgemein bekannten HTTP-Protokoll basiert, sollte es eigentlich auch von anderen Webservern unterstützt werden können ...

Statische Variantenbeschreibungen (type maps)[Bearbeiten]

Die Idee hierbei ist, dass durch die angesprochene URL auf dem Server nicht die zu übertragende Datei angesprochen wird, sondern eine Textdatei, welche die Verhandlungsstrategie des Webservers festlegt. Diese Datei beschreibt also, in welchen Fällen der Webserver welche tatsächliche Datei zurückliefern soll.

Eine solche Beschreibung besteht aus

  • einem Namen und
  • einer Liste von Dateibeschreibungen mit entsprechenden Eigenschaften.

Ganz allgemein gesprochen hat die Datei dasselbe Format wie die im RFC822 definierten Angaben eines Mail-Headers.

Zu diesen Eigenschaften gehören insbesondere MIME-Typen, Landessprachen und Qualitätsangaben (das sind Zahlenwerte zwischen 0 und 1).

Nehmen wir an, wir wollen eine Datei mit der URL test.var (in einem beliebigen Verzeichnis) definieren, welche ein HTML-Dokument in den Sprachen Deutsch bzw. Englisch beschreiben soll. Dann sollte die Datei test.var etwa folgenden Inhalt haben:

Beispiel
URI: test # wird von Apache ignoriert URI: test.html.en Content-type: text/html Content-language: en URI: test.html.de Content-type: text/html Content-language: de

Bei der Anforderung von test.var wird in diesem Falle entweder der Inhalt von test.html.en oder von test.html.de zurückgeliefert, falls der Browser wenigstens eine der beiden Landessprachen akzeptiert. Der Browser merkt er von der entsprechenden Verhandlung gar nichts - in der URL-Zeile sieht der Anwender weiterhin test.var, es ist keine redirection, die hier statt findet.

Das bedeutet allerdings, dass der Anwender aufgrund der Endung .var sehen kann, dass hier nicht 'einfach nur' ein HTML-Dokument zurückgeliefert wird. (Um dies zu verbergen, müsste man die Endung .html als Variantenbeschreibung definieren, und dies dann beschränkt auf Verzeichnisse mit den entsprechenden Dokumenten darin - das wiederum geht mit .htaccess sehr schön dezentral.)

Im obigen Beispiel wurde in beiden Varianten ein MIME-Typ für den Inhalt des Dokuments definiert. Diese Angabe scheint unverzichtbar zu sein - lässt man den Content-type an dieser Stelle weg, dann führt die 'Verhandlung' zu keinem positiven Ergebnis. In diesem Falle sendet der Apache-Webserver einen HTTP-Statuscode 406 (Not Acceptable) und generiert freundlicherweise dynamisch eine HTML-Seite mit einer entsprechenden Fehlermeldung sowie Verweisen auf alle definierten Alternativen (und deren Attributen); der Anwender muss sich dann explizit eine dieser Dateien aussuchen.

Weil das natürlich keine schöne Lösung ist, sollte der Webmaster diesen Fall besser aktiv behandeln und einen Standardwert für diese Auswahl definieren. In unserem Falle wäre das etwa eine Variante, der keine Sprache zugeordnet ist. Diese gilt dann immer als 'ausreichend' für die Anforderungen des Browsers, sie wird allerdings mit niedrigster Priorität als Ergebnis der Verhandlung ausgewählt - genau das, was wir haben wollen. Die Datei test.var wäre dafür also z. B. um die Zeilen

Beispiel
URI: test.html.default Content-type: text/html

zu erweitern. Die Datei test.html.default wird dabei normalerweise identisch mit einer der bereits vorhandenen Varianten sein. In diesem Falle kann man auf einem UNIX-Server statt einer Kopie einen symbolic link auf die betreffende Datei anlegen und verhindert damit, mehrere identische Kopien des Dokuments inhaltlich warten zu müssen. Natürlich muss der Webserver dazu die Verarbeitung von symbolic links für das Verzeichnis erlauben (Options FollowSymLinks in Apache).

An dieser Stelle sei lediglich darauf hingewiesen, dass dieser Mechanismus noch wesentlich mehr kann. Zwei typische Anwendungsbeispiele:

  • Moderne Browser verstehen schon das Graphikformat PNG, ältere nicht. Man könnte also eine Graphik in PNG und einem älteren Format anbieten; - versteht der Browser beides, dann wird er in der Liste seiner akzeptierten MIME-Typen möglicherweise selbst eine Prioritätenliste mitsenden, ansonsten können wir über die Qualitätsangaben selbst eine festlegen. Der Benutzer bekommt immer die beste lieferbare Graphik-Variante (PNG kann deutlich besser komprimieren als etliche andere Formate) und er braucht dafür kein aktives JavaScript, damit wir seine Browser-Version abfragen und daraus die passende Graphik berechnen können.
  • Eine installierte Browser-Erweiterung (plugin) könnte die Liste der akzeptierten MIME-Typen erweitern. Ein Dokument könnte beispielsweise in einer druckoptimierten Version, etwa in PDF, vorliegen, welches wiederum nur Browser mit der entsprechenden Erweiterung verstehen. Falls das installierte plugin die akzeptierten MIME-Typen des Browsers erweitert hat und dieser das dem Webserver über den HTTP-Header Accept mitteilt, dann kann der Webserver entscheiden, ob er die PDF- oder ersatzweise die HTML-Version zurückschicken muss, ohne den Besucher durch die Aufforderung, erst mal zusätzliche Software zu installieren, zu verschrecken.

Generische Variantenbeschreibungen (multiviews)[Bearbeiten]

Das also war die komplizierte Methode. bei der man die Variantendateien selber schreiben musste. Nachdem wir uns jetzt durch diese hindurchgearbeitet haben, kommt die Belohnung: Wenn man nur einen Teil der verfügbaren Fähigkeiten solcher Variantenbeschreibungen ausnutzen will, dann kann der Webserver sich diese selber erzeugen! Um zu versehen, wie er das tut, sind erst einmal wieder ein paar Grundlagen erforderlich.

Dateien dürfen beim Apache-Webserver generell mehrere Endungen haben (alles, was durch den ersten Punkt im Namen abgetrennt ist, gilt als Endung - für Details siehe die mod_mime-Dokumentation des Apache-Webservers). Insbesondere dürfen als Endungen auftreten:

Beispiel: Die Datei welcome.html.de wird vom Webserver als Dokument des MIME-Typs text/html und der Landessprache de erkannt werden - vorausgesetzt, in dessen Konfiguration sind diese beiden Abbildungen korrekt eingetragen.

Wie motiviert man nun den Webserver, sich eine Variantendatei zu generieren? Indem man die anzusprechende Datei nicht anlegt, aber für das entsprechende Verzeichnis die Eigenschaft Options +MultiViews setzt (also die gesetzten Optionen um MultiViews ergänzt).

Als Beispiel soll wieder genau der Fall dienen, der nach oben weiter oben schon über die statische Variantendatei gelöst worden war. Wir haben also die Dateien test.html.en und test.html.de zur Verfügung. Greift ein Besucher nun auf die URL des Dokuments test.html zu, dann

  • stellt der Apache-Webserver fest, dass das entsprechende Dokument nicht vorhanden ist,
  • erkennt durch die gesetzte MultiViews-Option, dass er nicht seine normale Fehlerbehandlung einleiten muss,
  • liest den Inhalt des Verzeichnisses,
  • erkennt diese beiden Dateien als Sprach-Varianten der gesuchten Datei und
  • erzeugt sich dynamisch eine Variantenbeschreibung, die mindestens so gut ist wie diejenige aus unserem vorherigen Beispiel.

Im Prinzip macht der Webserver also etwas ganz Ähnliches wie bei der Erzeugung von Fehlerdokumenten, die beim Apache ja schließlich auch konfigurierbar sind - es wird lediglich das Entscheidungsverfahren, welche Datei letztlich zurückgeliefert werden soll, an der passenden Stelle mit dynamischen Daten versehen und abgewickelt. Alles, was wir also zu tun haben, ist es, Dateien mit passenden Namen anzubieten; den Rest erledigt der Webserver von selbst.

Diese MultiViews haben zwei angenehme Nebeneffekte:

  • Die angesprochene URL des Dokuments lautet in diesem Falle test.html. Für den Besucher ist also - anders als bei den statischen Variantenbeschreibungen - gar nicht zu erkennen, dass eine dynamische Bestimmung des Dokumentinhalts stattgefunden hat.
  • Nachdem die MultiViews einmal aktiviert wurden, braucht man an der Konfiguration nichts mehr zu ändern. Insbesondere dürfen statische und variable Dokumente im selben Verzeichnis koexistieren; man kann also nach und nach bestehende HTML-Dokumente durch deren Sprachvarianten ersetzen oder weitere Sprachen hinzufügen.

Auch muss während der Umstellung kein einziger Verweis geändert werden, weil sich ja die tatsächlich angesprochenen URLs nicht ändern!

Der offensichtliche Nachteil dieses Verfahrens ist der mögliche Performance-Verlust. Wenn der Webserver bei jedem Zugriff auf ein MultiViews-Dokument das Verzeichnis analysieren, die Variantenbeschreibung berechnen und das passende Dokument zurückliefern soll, dann verursacht dies Last auf dem Webserver-Rechner. (Insbesondere sollte man dann nicht zuviele Dokumente in demselben Verzeichnis haben.)

Außerdem ist man eingeschränkt, was die Möglichkeiten der Formulierung von Verhandlungsstrategien betrifft: An Prioritätenlisten geht außer der Reihenfolge für Landessprachen nichts mehr, und komplexe Bedingungen unter Berücksichtigung mehrerer Attribute des Dokuments sind auch nicht mehr möglich. Aber gerade dass nur genau die Landessprache als Verhandlungsziel dienen soll, ist im Zusammenhang mit der Internationalisierung einer Web-Site ein häufig auftretender Fall. Ein solches Standardproblem läßt sich am besten durch eine Standardlösung erledigen, und genau dies sind eben die MultiViews von Apache.

Alternativen[Bearbeiten]

Und was tun, wenn man keinen Apache-Webserver hat?

Die Beschreibung dessen, was der Browser an Wünschen gesendet hat, ist auch über Variablen der CGI-Schnittstelle ansprechbar, so dass ein Entwickler das beschriebene Verhalten ggf. durch eine CGI-Anwendung (beispielsweise in der Fehlerbehandlung des Webservers) selbst realisieren könnte.

  • HTTP_ACCEPT stellt Informationen über die akzeptierten MIME-Typen im empfangenen HTTP-Header zur Verfügung. (Das scheinen alle bekannten Browser zu senden, auch Netscape 3 und Microsoft 2; Netscape 4.5 sendet hier beispielsweise, dass er schon die MIME-Typen img/pjpeg und img/png kennt.)
  • HTTP_ACCEPT_CHARSET enthält ggf. akzeptierte Zeichensätze. (Netscape 4.5 sendet hier einen Wert.)
  • HTTP_ACCEPT_ENCODING enthält ggf. akzeptierte Codierungen, also z. B. die Angabe, dass der Browser auch spezielle (z. B. komprimierte) Datenformate verarbeiten kann usw. (Netscape 4.5 akzeptiert beispielsweise schon das encoding gzip, Microsoft Internet Explorer 5 zusätzlich auch noch deflate.)
  • HTTP_ACCEPT_LANGUAGE enthält ggf. akzeptierte Landessprachen.

Diese Variablen sind in der CGI-Norm implizit spezifiziert: CGI liest alles, was im HTTP-Header kommt, ersetzt '-' durch '_' in Variablennamen, fügt jeweils die Zeichenkette HTTP_ davor und setzt es ins Environment. (Wie die Variablen heißen werden, das kann man dem genormten Aufbau des HTTP-Headers entnehmen.) Letztlich hilft nur Ausprobieren, was welcher Browser bei geeigneter Konfiguration senden kann, und prüfen, welche CGI-Variablen in welchen Fällen tatsächlich gesetzt werden. Gute Defaults muss man für die Verhandlung ja ohnehin vorsehen ...

Content Negotiation und Caches[Bearbeiten]

Ein besonderes Problem soll wenigstens am Rande erwähnt werden: Was passiert mit mehrdeutigen Inhalten von URLs, die in Zwischenspeichern (Caches von Browsern bzw. Proxy-Servern) aufbewahrt werden sollen bzw. könnten? Wie merkt ein solcher Zwischenspeicher, dass der Inhalt in diesem Falle durch den URL gar nicht eindeutig beschrieben ist? Es droht ja beispielsweise, dass ein Proxy-Server aus seinem Cache eine Seite an einen Browser ausliefert, der im Falle der tatsächlichen Verhandlung mit dem Webserver eine Seite mit ganz anderem Inhalt hätte bekommen müssen (weil die von diesem Browser gelieferten HTTP-Header sich von denen derjenigen Anforderung, welche den Inhalt des Proxy-Cache verursacht hat, unterscheiden?

Der Proxy-Server hat keine realistische Möglichkeit, alle möglichen alternativen Inhalte desselben URL zu speichern - dafür sind es in der Regel einfach zu viele. Ohne entsprechende Information durch den Webserver kann er noch nicht einmal erkennen, dass überhaupt ein Problem vorliegen könnte.

Also muss der Webserver etwas tun. Dafür hat er zwei Möglichkeiten zur Verfügung:

  • Er kann HTTP-Header senden, die beliebigen Caches das Speichern der Seite verbieten. In HTTP/1.1 kann man dabei sogar zwischen Browser- (Cache-control: private) und Proxy-Caches (Cache-control: public) unterscheiden; ältere Browser und vor allem viele Proxy-Server verstehen jedoch nur HTTP/1.0, und um solchen Proxy-Servern klar zu machen, dass sie die Seite nicht speichern sollen, müsste man das Speichern leider auch im Browser verbieten (was die Performance der Übertragung durch die dann zusätzlich erforderlichen Zugriffe bremst).
  • Er kann HTTP-Header senden, die den Inhalt der Seite als Ergebnis einer Verhandlung kennzeichnen (Vary:). Dabei kann der Server dem Proxy sogar mitteilen, welche HTTP-Header der Anforderung eine Auswirkung auf das Ergebnis der Verhandlung hatten, so dass der Proxy sogar in der Lage wäre, in einem Teil der Fälle diese Verhandlung selbst zu führen (denn er kann ja speichern, welche HTTP-Header in der ursprünglichen Anforderungen zum Cache-Inhalt geführt haben). Derzeit unterstützt kein mir bekannter Proxy-Server diese Art der Verhandlung; einige Proxy-Server (z. B. Squid) erkennen jedoch immerhin den Vary:-Header und speichern dann den Inhalt der Seite nicht.

Literatur[Bearbeiten]

  • Apache Server: Content Negotiation
    • Apache Server: Module mod_negotiation
      Die Beschreibung des Moduls zur Auswertung der content negotiation enthält u. a. die detaillierte Beschreibung des Aufbaus einer Variantendatei (type map).
    • Apache Server: Module mod_mime
      Die Beschreibung des Moduls zur Erkennung von Dateitypen enthält u. a. die detaillierte Beschreibung der Erkennung von Endungen in Dateinamen.