Webentwicklung

HTTP-Header Vary — Verhindern, dass ausgehandelte Responses durcheinandergeraten

HTTP-Header Vary — Verhindern, dass ausgehandelte Responses durcheinandergeraten

HTTP-Header Vary — Verhindern, dass ausgehandelte Responses durcheinandergeraten

Eine URL liefert nicht immer exakt dieselbe Response. Ein Server kann die Darstellung anhand der bevorzugten Sprache, des Komprimierungsformats oder des akzeptierten Medientyps auswählen. Diese Flexibilität ist nützlich, stellt aber jeden Cache vor eine Frage: Wann darf eine für eine Anfrage erzeugte Response für eine andere Anfrage wiederverwendet werden?

Der HTTP-Response-Header Vary ist ein Teil der Antwort. Er aktiviert kein Caching, legt keine Gültigkeitsdauer fest und wählt keine beste Darstellung aus. Stattdessen teilt er einem Cache mit, welche Request-Header die Response beeinflusst haben, damit unterschiedliche Varianten nicht als austauschbar behandelt werden.

Eine Ressource, mehrere Darstellungen

HTTP unterscheidet zwischen einer Ressource und einer Darstellung dieser Ressource. Eine URL kann mehrere Darstellungen haben: ein HTML-Dokument in verschiedenen Sprachen, eine komprimierte oder unkomprimierte Response oder ein Bild, das anhand der Client-Präferenzen ausgewählt wird.

Das nennt man server-driven oder proactive content negotiation. Der Client sendet Hinweise wie Accept, Accept-Encoding oder Accept-Language. Der Server wendet seinen eigenen Auswahlalgorithmus an und liefert eine Darstellung zurück. MDNs Leitfaden zur Content Negotiation weist auf eine wichtige Grenze hin: Der Algorithmus ist serverspezifisch. Eine Präferenz in der Anfrage legt nicht automatisch fest, welche Darstellung der Server wählen muss.

Eine Anfrage an /guide mit Accept-Language: de könnte deutsches HTML erhalten. Eine andere Anfrage an dieselbe URL mit Accept-Language: en könnte englisches HTML erhalten. Die URL ist gleich, die Response aber nicht.

Was Vary beschreibt

Vary ist ein Response-Header. Sein Wert listet die Request-Header-Felder auf, die die Response beeinflusst haben:

HTTP/1.1 200 OK
Content-Type: text/html; charset=UTF-8
Vary: Accept-Language

<html>...</html>

Das bedeutet, dass die Auswahl von Accept-Language abhing. Es bedeutet nicht, dass jede Sprache verfügbar ist, und erklärt dem Cache auch nicht den Auswahlalgorithmus des Servers. Es benennt lediglich die Eingabe, die der Cache berücksichtigen muss, wenn er eine gespeicherte Response wiederverwenden möchte.

Dasselbe gilt für Komprimierung:

Vary: Accept-Encoding

Wenn ein Server eine komprimierte Darstellung sendet, sobald der Client Brotli akzeptiert, dürfen diese Anfragen nicht allein wegen gleicher URL und gleicher Methode als dieselbe Variante gelten.

Die formale Definition steht in RFC 9110, Abschnitt 12.5.5. Die praktische Zusammenfassung in MDNs Vary-Referenz ist hilfreich: Der Header beschreibt die Teile der Anfrage, abgesehen von Methode und URL, die die Response beeinflusst haben.

Wie ein Cache den Header verwendet

Ein Cache benötigt mindestens Request-Methode und Ziel-URI, um eine gespeicherte Response zu finden. Bei Vary: Accept-Language reicht das nicht. Der Cache vergleicht zusätzlich das Feld Accept-Language der neuen Anfrage mit dem Feld der Anfrage, durch die die gespeicherte Response entstanden ist.

RFC 9111, Abschnitt 4.1 beschreibt dies als Matching-Anforderung. Stimmen die genannten Felder nicht überein, darf der Cache die gespeicherte Response nicht ohne Revalidierung wiederverwenden. Er muss normalerweise eine andere passende Variante finden oder die Anfrage an den Origin weiterleiten.

Ein nützliches Denkmodell:

  1. Die URL identifiziert die Ressource.
  2. Der Vary-Wert der Response nennt die Request-Felder, die die Auswahl beeinflusst haben.
  3. Der Cache vergleicht diese Felder vor der Wiederverwendung.
  4. Nur eine passende und anderweitig wiederverwendbare Response darf die neue Anfrage beantworten.

Das bedeutet nicht, dass jeder Cache intern eine Zeichenkette aus URL und Header-Werten bildet. Implementierungen dürfen unterschiedlich aufgebaut sein. Das Protokoll regelt die Eignung zur Wiederverwendung, nicht eine bestimmte Datenstruktur.

Auch die Standard-Response zählt

Ein häufiger Fehler ist, Vary nur dann zu setzen, wenn die Anfrage ausdrücklich eine Präferenz enthält. Liefert ein Server ohne Accept-Language eine Standardsprache, mit dem Feld aber eine andere Sprache, entsteht auch die Standard-Response aus derselben Auswahlregel.

Darum sollte der Vary-Wert für die Responses einer URL konsistent sein, einschließlich der Standard-Response. Die Caching-Spezifikation warnt, dass das Weglassen des Headers in der Standard-Response dazu führen kann, dass diese später gewählt wird, obwohl eine passendere Variante existiert.

Dasselbe gilt für eine 304 Not Modified-Response. Sie enthält keinen neuen Darstellungs-Body, ihre Metadaten wirken aber am Aktualisierungsprozess des Caches mit. Konsistente Vary-Metadaten sind daher keine kosmetische Einzelheit.

Was bedeutet Vary: *?

Der Wildcard-Wert hat eine besondere Bedeutung:

Vary: *

Er zeigt an, dass Informationen außerhalb der genannten Request-Header die Response-Auswahl beeinflusst haben. Ein Cache kann diese Auswahl nicht allein durch Header-Vergleich nachvollziehen. Nach den HTTP-Caching-Regeln besteht eine gespeicherte Response mit diesem Wildcard-Wert das normale Varianten-Matching nicht.

Der Stern ist kein allgemeines Mittel, um viele Header aufzulisten. Wenn Accept und Accept-Encoding die Response beeinflusst haben, werden sie ausdrücklich genannt:

Vary: Accept, Accept-Encoding

Umgekehrt können viele Header mit hoher Vielfalt sehr viele Varianten erzeugen und den Nutzen eines Shared Cache verringern. MDN weist darauf hin, dass server-driven Negotiation Shared Caches weniger effizient machen und mehr Informationen über Client-Präferenzen preisgeben kann. Der beste Wert ist daher nicht die längste, sondern die kleinste korrekte Liste.

Language Negotiation ist keine vollständige Präferenz

Accept-Language wirkt für mehrsprachige Websites praktisch, sollte aber als Hinweis behandelt werden. Der Browserwert spiegelt oft die Sprache seiner Oberfläche wider, nicht unbedingt die Sprache, die eine Person auf jeder Website lesen möchte. Außerdem können Menschen ein gemeinsames Gerät verwenden oder mehrere Sprachen verstehen.

MDN empfiehlt eine Möglichkeit zur manuellen Auswahl, etwa ein Sprachmenü, und danach die explizite Auswahl zu respektieren. Das ist eine Produkt- und Informationsarchitekturentscheidung, die Vary nicht lösen kann.

Bei stabilen Sprach-URLs wie /en/guide, /id/panduan und /de/anleitung macht die URL die gewählte Darstellung deutlich. Das kann Mehrdeutigkeit für Leser, Links, Lesezeichen und Caches reduzieren. Es ist nicht für jede Anwendung automatisch besser, aber oft leichter zu verstehen als eine stille Änderung derselben URL anhand eines Browser-Hinweises.

Checkliste für ein Review

Bei einer ausgehandelten Response würde ich folgende Fragen stellen, ohne anzunehmen, dass ein bestimmtes Framework oder CDN bereits die richtige Entscheidung getroffen hat:

  • Kann dieselbe URL inhaltlich unterschiedliche Darstellungen liefern?
  • Welche Request-Felder haben die Auswahl tatsächlich beeinflusst?
  • Werden diese Felder in Vary genannt?
  • Verwendet die Standard-Response dieselben relevanten Metadaten?
  • Bewahren 304-Responses die nötigen Vary-Informationen?
  • Wären eine explizite URL oder eine manuelle Auswahl verständlicher als automatische Negotiation?
  • Werden private oder sensible Responses getrennt von normalen öffentlichen Varianten betrachtet?

Diese Checkliste beweist nicht, dass ein Production-Cache korrekt konfiguriert ist. Reverse Proxy, CDN, Anwendungsframework und Browser können jeweils eigene Regeln haben. Sie ist ein Ausgangspunkt, um die tatsächlich gesendeten Response-Header und die vom Programm verwendeten Anfrage-Dimensionen zu untersuchen.

Fazit

Vary wird leicht übersehen, weil er den Body für den Leser nicht verändert. Seine Aufgabe ist zu erklären, warum dieser Body ausgewählt wurde, damit ein Intermediary ihn nicht für eine unpassende Anfrage wiederverwendet. Deshalb ist er zuerst ein Signal für Korrektheit und erst danach ein Performance-Feature.

Die praktische Lehre ist zurückhaltend: Wenn sich eine Response wegen eines Request-Headers ändert, sollte diese Abhängigkeit sichtbar sein. Explizite Sprach-URLs oder eine explizite Auswahl sind sinnvoll, wenn sie das System verständlicher machen. Wenn die Entscheidung von Faktoren abhängt, die sich nicht durch Request-Header darstellen lassen, sollte man nicht annehmen, dass ein Cache sie allein aus der URL erraten kann.

References