Leistungen Referenzen Notfallservice Kontakt
    KONTAKT.

    Konsolutions | Full-Service-Agentur
    Volker Königshofen
    MĂŒhlenbachstr. 40
    41462 Neuss

    Fon: +49 172 2485226 (auch Whatsapp)
    Fax: +49 2131 5394167
    Mail: info@koenigshofen.com/blog

    USt-IdNr.: DE255840543

    Kontaktformular
    Unser Team

    Haendlerbund

    Eine API soll standardmĂ€ĂŸig JSON liefern, aber manche Clients möchten XML. Eine Website soll Deutsch zeigen, wenn der Browser Deutsch bevorzugt. Und ein Bild-Endpoint soll AVIF liefern, wenn der Browser es kann, sonst WebP oder JPEG. Genau fĂŒr solche FĂ€lle gibt es Content Negotiation (Inhaltsaushandlung) in HTTP: Client und Server einigen sich ĂŒber Header darauf, welches Format, welche Sprache oder welche Codierung am besten passt.

    In der Praxis wird das Thema oft unterschĂ€tzt. Dann entstehen Endpoints wie /api/v1/data.json, ?lang=de oder separate Routen pro Format. Das funktioniert, ist aber hĂ€ufig schwer zu pflegen und fĂŒhrt zu Inkonsistenzen. Mit sauberer Aushandlung ĂŒber Header bleibt die URL stabil und die Regeln sind an einer Stelle konzentriert.

    WofĂŒr Content Negotiation im Alltag wirklich genutzt wird

    Formatwahl: JSON, HTML, XML oder CSV

    Die bekannteste Variante ist die Formatwahl ĂŒber den Accept-Header. Ein Client sagt damit, welche Medien-Typen (MIME Types) er akzeptiert, zum Beispiel:

    • application/json fĂŒr JSON
    • text/html fĂŒr HTML
    • application/xml fĂŒr XML
    • text/csv fĂŒr CSV

    Wichtig: Der Server entscheidet am Ende. Der Client Ă€ußert nur PrĂ€ferenzen. Wenn ein Format nicht angeboten wird, sollte der Server das klar signalisieren (dazu spĂ€ter mehr).

    Sprachen: Deutsch vs. Englisch

    FĂŒr Sprache ist Accept-Language zustĂ€ndig, etwa de-DE,de;q=0.9,en;q=0.8. Browser schicken diesen Header automatisch. Der Server kann damit zum Beispiel:

    • die richtige Übersetzung wĂ€hlen,
    • Datums-/Zahlenformate lokalisiert ausgeben,
    • Fallbacks nutzen (z. B. erst de-DE, dann de, dann en).

    Wenn eine App zusÀtzlich eine explizite Spracheinstellung im Profil hat, kann diese Vorrang bekommen. Content Negotiation ist dann ein guter Default, aber nicht die einzige Quelle.

    Kompression und Varianten (kurzer Überblick)

    Es gibt weitere Formen, z. B. Aushandlung von Kompression ĂŒber Accept-Encoding oder Bildformaten ĂŒber Accept (z. B. image/avif). Diese Logik ist Ă€hnlich, nur der Fokus ist ein anderer. Der Kern bleibt: Client sendet PrĂ€ferenzen, Server wĂ€hlt eine passende Variante.

    So lesen Server die Header: Werte, PrioritÀten und q-Faktoren

    Was bedeutet q=0.8?

    In Accept-Headern können PrioritĂ€ten ĂŒber sogenannte QualitĂ€tsfaktoren (q-Werte) angegeben werden. Beispiel:

    • Accept: application/json;q=1.0, application/xml;q=0.8, */*;q=0.1

    Das bedeutet: JSON ist am liebsten, XML geht auch, und „irgendwas“ ist nur Notlösung. Wenn kein q angegeben ist, gilt implizit q=1.0.

    Wildcards sind erlaubt – aber tĂŒckisch

    Viele HTTP-Clients senden standardmĂ€ĂŸig Accept: */*. Das heißt nicht „liefere alles“, sondern „mir ist das Format egal“. FĂŒr APIs ist es sinnvoll, dann einen klaren Standard zu definieren (meist JSON) und nicht zufĂ€llig HTML zu liefern, nur weil derselbe Host auch eine Website ausliefert.

    Warum Reihenfolge allein nicht reicht

    Manche Entwickler verlassen sich auf die Reihenfolge in der Header-Liste. Das ist riskant: Ausschlaggebend ist primÀr q, nicht die Position. Eine robuste Implementierung wertet q korrekt aus und nutzt Reihenfolge nur als Tie-Breaker (wenn zwei Optionen den gleichen q-Wert haben).

    Robuste Umsetzung auf dem Server: Regeln, Defaults, klare Fehler

    Schritt 1: UnterstĂŒtzte Varianten definieren

    Startpunkt ist immer eine feste Liste von Varianten, die der Server wirklich liefern kann. Zum Beispiel:

    • Format: application/json, text/csv
    • Sprache: de, en

    Diese Liste sollte nicht „theoretisch“ sein, sondern tatsĂ€chlich implementiert. Sonst entstehen Situationen, in denen ein Client ein Format korrekt anfragt, aber der Server unvollstĂ€ndige Daten liefert.

    Schritt 2: Sinnvolle Defaults festlegen

    Wenn der Client keine PrÀferenz sendet (oder nur */*), braucht es einen Default. Typisch:

    • API: JSON als Standard
    • Website: HTML als Standard
    • Sprache: z. B. Deutsch oder Englisch, abhĂ€ngig vom Projekt

    Wichtig ist die Konsistenz: Ein Endpoint sollte nicht je nach Client „mal so, mal so“ wirken. Wenn eine Route eine API ist, sollte sie im Zweifel immer API-Verhalten zeigen.

    Schritt 3: Fehlersituationen sauber abbilden

    Wenn der Client ausschließlich Formate anfragt, die nicht unterstĂŒtzt werden, ist ein „best effort“ oft keine gute Idee. Dann ist ein klarer HTTP-Fehler hilfreicher. Bei Formatwahl ist dafĂŒr ĂŒblich:

    • HTTP 406 (Not Acceptable), wenn kein angefragtes Format lieferbar ist

    FĂŒr Sprache gilt das strenger selten, weil ein Fallback (z. B. auf Englisch) meist akzeptabel ist. Dennoch sollte die Anwendung einheitliche Regeln haben: Entweder Sprache ist „verhandelbar mit Fallback“, oder Sprache ist „hart“ und fĂŒhrt zu einer Fehlermeldung.

    Praktische Schritte fĂŒr ein sauberes Setup

    • Auf dem Server eine kleine Funktion bauen, die den Accept-Header gegen eine Whitelist matcht (inklusive q-Werten).
    • FĂŒr APIs einen Default (z. B. JSON) definieren, wenn Accept fehlt oder */* ist.
    • Bei Sprache zuerst eine explizite Einstellung (z. B. Benutzerprofil) berĂŒcksichtigen, danach Accept-Language, danach Fallback.
    • Bei nicht unterstĂŒtzten Formaten konsequent mit 406 antworten, statt „irgendwas“ zu liefern.
    • Die tatsĂ€chlich gewĂ€hlte Variante im Response klar machen (Content-Type setzen, ggf. Content-Language).

    Typische Stolperfallen in APIs und Webapps

    Format in die URL packen: schnell gebaut, schwer gepflegt

    URLs wie /resource.json oder /resource.xml sind simpel, aber fĂŒhren schnell zu doppelten Routen und doppelter Dokumentation. Außerdem wird Caching unĂŒbersichtlich, weil unterschiedliche Varianten zwar unterschiedliche URLs haben, aber fachlich denselben „Ressourcen-Namen“ tragen.

    Sprache per Query-Parameter: okay, aber mit klaren Regeln

    ?lang=de kann sinnvoll sein (z. B. fĂŒr sharebare Links). Dann sollte aber klar sein, wie es mit Accept-Language zusammenspielt: Query ĂŒberschreibt Header, oder umgekehrt. Ohne feste PrioritĂ€t entstehen schwer reproduzierbare Bugs.

    Cache-Fallen: Varianten brauchen saubere Trennung

    Wenn ein Endpoint je nach Accept oder Accept-Language unterschiedliche Inhalte liefert, muss Caching das berĂŒcksichtigen. Sonst kann es passieren, dass ein Cache Deutsch speichert und spĂ€ter Englisch ausliefert (oder umgekehrt). In solchen FĂ€llen ist der HTTP-Header Vary entscheidend: Er sagt Caches, dass die Antwort je nach bestimmten Request-Headern variiert. Typisch sind Vary: Accept und/oder Vary: Accept-Language.

    Wer bereits Caching nutzt, kann das Thema gut mit HTTP Caching: Cache-Control und ETag richtig nutzen zusammendenken, weil Varianten und Cache-Strategie zusammengehören.

    Mini-Fallbeispiel: Ein Endpoint, zwei Formate, zwei Zielgruppen

    Ausgangslage

    Ein Team betreibt einen Endpoint /reports. Intern nutzt das Dashboard JSON. Externe Partner möchten regelmĂ€ĂŸig CSV importieren. Anfangs gab es zwei Routen: /reports (JSON) und /reports.csv (CSV). Das fĂŒhrte zu doppelter Authentifizierung, doppelter Dokumentation und zwei Fehlerquellen.

    Lösung ĂŒber Accept

    Beide Clients nutzen dieselbe URL, aber senden unterschiedliche Header:

    • Dashboard: Accept: application/json
    • Partner: Accept: text/csv

    Der Server liefert die passende ReprÀsentation und setzt Content-Type entsprechend. Wenn ein Client etwas Unbekanntes anfragt, kommt 406 mit einer klaren Fehlermeldung. Ergebnis: weniger Routen, weniger Dokumentationsaufwand, und Format-Erweiterungen sind einfacher.

    Vergleich: Header-Aushandlung vs. separate Endpoints

    Ansatz Vorteile Nachteile
    Header (Accept, Accept-Language) Eine URL pro Ressource, klare Standards, gut erweiterbar Erfordert saubere Implementierung (q, Vary), Debugging ĂŒber Header nötig
    Separate URLs pro Format Schnell zu verstehen, leicht manuell im Browser testbar Doppelte Routen/Docs, hÀufiger Drift zwischen Varianten
    Query-Parameter (z. B. ?format=csv) Sharebare Links, einfach in Tools Oft Mischformen ohne klare PrioritÀt, kann mit Caching kollidieren

    Wie das mit API-Design und Fehlern zusammenhÀngt

    Klare Antworten statt „zufĂ€llig passend“

    Content Negotiation ist kein Ersatz fĂŒr gutes API-Design, aber ein Baustein davon. Wer Formate aushandelt, sollte auch Fehler konsistent modellieren: Wenn ein Client ein falsches Format anfragt, ist das ein anderes Problem als „falsche Daten gesendet“. FĂŒr die grundsĂ€tzliche Fehlerlogik hilft API-Fehler richtig behandeln.

    Security: Nicht alles akzeptieren, was ein Client behauptet

    Header sind Eingaben. Sie sollten daher nicht blind vertrauenswĂŒrdig sein. Statt „Accept: application/pdf“ automatisch zu bedienen, sollte der Server nur aus bekannten, implementierten Varianten wĂ€hlen. Das reduziert AngriffsflĂ€che und verhindert unerwartete Content-Type-Ausgaben.

    HĂ€ufige Fragen aus der Praxis

    Reicht es, immer JSON zu liefern und Accept zu ignorieren?

    FĂŒr viele private APIs ja, solange es dokumentiert und konsistent ist. SpĂ€testens wenn mehrere Clients oder Export-Formate dazukommen, lohnt sich Content Negotiation, weil sie spĂ€tere Änderungen ohne neue URLs ermöglicht.

    Sollte Sprache ĂŒber Accept-Language oder ĂŒber einen Parameter gesteuert werden?

    FĂŒr Websites ist Accept-Language ein guter Start, weil Browser ihn automatisch senden. FĂŒr Apps mit Nutzerprofil ist eine explizite Einstellung oft besser. Wenn Links teilbar sein mĂŒssen, ist ein Parameter sinnvoll, aber mit klarer PrioritĂ€tsregel.

    Kann Content Negotiation Breaking Changes vermeiden?

    Sie kann helfen, neue Formate parallel anzubieten, ohne alte abzuschalten. FĂŒr echte Versionierung (z. B. unterschiedliche Felder im JSON) ist das aber nicht gedacht. DafĂŒr ist ein eigenes Versionierungs-Konzept besser geeignet, zum Beispiel wie in API Versioning verstehen beschrieben.

    Welche Header sollten Responses setzen?

    Mindestens Content-Type. Bei Sprache zusÀtzlich Content-Language. Und wenn sich Antworten je nach Header unterscheiden, sollte Vary gesetzt werden, damit Caches korrekt arbeiten.

    Share.
    Avatar-Foto

    Königshofen Digital - Websites, E-Commerce, SEO/SEA, Google Ads, Branding und Automation mit KI. Liefert effiziente, automatisierte und messbare Lösungen aus einer Hand.