- Die URL-Struktur fungiert nicht nur als einfache Adresse, sondern auch als Mittel zum Speichern und Wiederherstellen von Anwendungszustand
- Am Beispiel der PrismJS-Download-Seite wird gezeigt, wie sich mit einer einzigen URL Theme-, Sprach- und Plugin-Einstellungen vollständig reproduzieren lassen
- Einzelne Bestandteile wie Pfad, Query-Parameter und Fragment drücken unterschiedliche Zustände aus, etwa hierarchische Navigation, Filterung oder Client-Navigation
- Suchfilter, Paginierung, Ansichtsmodus und Datumsbereich eignen sich gut für die URL, während sensible Informationen oder flüchtige UI-Zustände ungeeignet sind
- Gut gestaltete URLs erhöhen Teilbarkeit, Vorhersagbarkeit und Cache-Effizienz und stärken damit Zuverlässigkeit und Nutzererlebnis von Webanwendungen
Das Potenzial der URL
- Eine URL ist nicht nur eine einfache Ressourcenadresse, sondern fungiert auch als Benutzeroberfläche (UI) und Zustandscontainer
- Über Teilen, Lesezeichen, Browser-Verlauf und Deep Links bleibt Zustand automatisch erhalten
- Seit 1991 dient sie als grundlegender Mechanismus zur Zustandsverwaltung im Web
- Jeder Bestandteil einer URL drückt eine andere Art von Zustand aus
- Pfad (Path): hierarchische Ressourcennavigation (
/users/123/posts)
- Query: Filter, Optionen, Einstellungen (
?theme=dark&lang=en)
- Fragment: Position innerhalb eines Dokuments oder SPA-Routing (
#features, #/dashboard)
- Die Funktion Text Fragments ermöglicht Direktlinks zu bestimmtem Text innerhalb einer Seite
Muster für Query-Parameter
- Mehrere Werte können mit einem Trennzeichen (delimiter) unter einem Schlüssel zusammengefasst werden (
?tags=frontend,react,hooks)
- Verschachtelte Daten lassen sich als JSON oder Base64 serialisieren (
?config=eyJyaWNrIjoicm9sbCJ9==)
- Boolesche Flags können durch die bloße Existenz eines Schlüssels dargestellt werden (
?mobile)
- Die Array-Notation (bracket notation) stellt mehrere Werte in der Form
tags[]=frontend&tags[]=react dar
- Wird von
qs in Node oder Express-Middleware automatisch erkannt, ist aber nicht standardisiert
- Entscheidend ist, Konsistenz beizubehalten
Beispiele für Zustandsdarstellung per URL
- PrismJS: Speichert komplette Einstellungen für Theme, Sprache und Plugins im URL-Hash
- GitHub: Hebt mit
#L108-L136 einen bestimmten Bereich von Codezeilen hervor
- Google Maps: Enthält Koordinaten, Zoom-Stufe und Kartentyp in der URL
- Figma: Teilt Arbeitskontext wie Canvas-Position, Zoom und ausgewählte Elemente per URL
- E-Commerce-Websites: Legen Filter, Sortierung und Preisbereich in der URL ab, um den Suchzustand wiederherzustellen
Frontend-Engineering-Muster
- Zustände, die sich für die URL eignen
- Suchbegriffe, Filter, Seiten- und Sortierzustand, Ansichtsmodus, Datumsbereich, aktiver Tab, UI-Konfiguration, Feature-Flags
- Zustände, die sich nicht für die URL eignen
- Sensible Informationen wie Passwörter oder Tokens, temporäre UI-Zustände, ungespeicherte Eingaben, große Datenmengen, Zustände mit hoher Änderungsfrequenz
- Maßstab für die Entscheidung: Soll ein anderer Nutzer beim Klick auf dieselbe URL denselben Zustand sehen?
JavaScript-Implementierung
- Mit der API
URLSearchParams lassen sich Query-Parameter lesen und schreiben
pushState fügt einen neuen Verlaufseintrag hinzu, replaceState aktualisiert den aktuellen Eintrag
- Über das Ereignis
popstate kann die UI beim Zurück-Navigieren im Browser wiederhergestellt werden
React-Implementierung
- Mit dem Hook
useSearchParams aus React Router lässt sich URL-Zustand kompakt verwalten
- Beim Lesen und Aktualisieren von Parametern werden URL und UI automatisch synchronisiert
Best Practices für URL-Zustandsverwaltung
- Standardwerte nicht in die URL aufnehmen (
?theme=dark beibehalten, Standardwerte im Code behandeln)
- Mit Debouncing übermäßige URL-Aktualisierungen während der Eingabe vermeiden (
lodash.debounce verwenden)
- pushState vs replaceState
pushState: für rückgängig machbare Zustände wie Filteränderungen oder Seitenwechsel
replaceState: für feingranulare Änderungen wie Sucheingaben
Die URL als Vertrag verstehen
- Eine gut gestaltete URL fungiert als expliziter Vertrag zwischen Anwendung und Nutzer
- Sie macht Grenzen zwischen öffentlich/privat, Client/Server und geteiltem/sitzungsgebundenem Zustand klar
- Gut lesbare URLs machen Absichten verständlich und sind für Menschen wie Maschinen gleichermaßen nachvollziehbar
- Eine Form wie
example.com/products/laptop?color=silver&sort=price vermittelt Bedeutung besonders gut
- Verbesserte Cache-Effizienz
- Dieselbe URL gilt als dieselbe Ressource, was die Cache-Trefferquote erhöht
- Über Query-Parameter lassen sich Cache-Varianten steuern
- Versionsverwaltung und Experimente
- API-Versionen und A/B-Tests lassen sich mit
?v=2, ?beta=true, ?experiment=new-ui unterscheiden
Antipatterns, die man vermeiden sollte
- In SPAs nur In-Memory-Zustand halten, wodurch der Zustand beim Neuladen verloren geht
- Sensible Informationen in die URL aufnehmen (
?password=secret123)
- Unklare Parameternamen (
?foo=true&bar=2 statt ?mobile=true&page=2)
- Komplexes JSON in Base64 kodieren und dadurch übermäßig lange URLs erzeugen
- URL-Längenlimits überschreiten (es gibt Beschränkungen bei Browsern, Servern und CDNs)
- Den Zurück-Button entwerten (durch übermäßige Verwendung von
replaceState)
Fazit
- Eine gute URL verweist nicht nur auf Inhalte, sondern drückt den Dialog zwischen Nutzer und Anwendung aus
- Die URL ist das älteste und eleganteste Mittel der Zustandsverwaltung für Absicht, Kontext und Teilbarkeit
- Es gibt zwar komplexe Tools zur Zustandsverwaltung wie Redux, MobX, Zustand und Recoil,
aber die grundlegende Funktion der URL nicht zu vergessen, ist die eigentliche Stärke des Webs
- Eine App, die beim Neuladen ihren Zustand verliert, verfehlt eine wesentliche Eigenschaft des Webs
2 Kommentare
Hacker-News-Kommentare
Beim Code-Review versuche ich, möglichst viel Status (state) in der URL zu speichern
Dass man nach dem Neuladen an einer völlig anderen Stelle landet oder eine geteilte URL einen ganz anderen Bildschirm zeigt, ist aus Nutzersicht eine Zumutung
Dieser Ansatz verlangsamt zwar die Entwicklung, aber im Team steigt dadurch das UX-Bewusstsein, und man sieht klarer, wie viel Status in einer View steckt
Es gibt zwar die Sorge, dass die URL zu einer Art öffentlicher API wird und dadurch Einschränkungen entstehen, aber die meisten URLs werden ohnehin nur kurzfristig genutzt, daher halte ich das für kein großes Problem
Falls nötig, lässt sich das mit Code lösen, der beim Laden alte URLs auf neue URLs migriert
Ich denke, mit Query-Parametern statt des Pfads wäre es etwas besser
Aus Nutzersicht ist das verwirrend, weil das Wort „Zurück“ mit dem Browser-Button verknüpft ist
Dass ein Neuladen den Status zurücksetzt, ist weniger nervig. Denn „Neu laden = von vorn anfangen“ ist ein verbreitetes mentales Modell
Wenn alles mit JS verarbeitet wird, gehen solche Grundfunktionen oft auf subtile Weise kaputt
Trotzdem habe ich in der Zusammenarbeit mit über 30 UX-Designern noch nie Richtlinien zu URLs bekommen
Gerade auf Mobilgeräten ist es oft schwer, eine Seite in den Ausgangszustand zurückzubringen, sodass Neuladen die schnellste Lösung ist
Bei Infinite Scroll oder komplexen Filter-UIs ist das Zurücksetzen umso lästiger, je mehr Status in der URL steckt
Wenn man ohnehin schon mit einer schlechten UX kämpft und dann auch noch die URL aufräumen muss, ist das für Nutzer doppelter Stress
Ich habe das Gefühl, dass selbst digital versierte Menschen URL und DNS nur schlecht verstehen
Man sollte Phishing-Risiken verringern können, die Bedeutung von URL-Parametern (
?t=_,utm_) verstehen und vor dem Teilen personenbezogene Daten entfernen könnenMan sollte auch wissen, dass das HTTPS-Schloss nicht automatisch „Vertrauen“ bedeutet
Wenn man URLs als Status-Container verwendet, wird die interne Struktur offengelegt, und Versionierung wird notwendig
Auch bei Browser-Kompatibilität oder Authentifizierungsabläufen kann es Probleme geben
Trotzdem versuche ich, möglichst viel Status in der URL offenzulegen, ähnlich wie bei Kommandozeilenargumenten
Das ist jedoch ein bewusster Trade-off und nicht das Ergebnis von Unwissen oder mangelnder Erfahrung
Ich empfehle Rison, eine alte Bibliothek, die aber immer noch nützlich ist
Damit lässt sich JSON sauber in einer URL speichern, und sie wird auch in Elastic Kibana verwendet
Beispiel: http://example.com/service?query=q:'*',start:10,count:10
Wenn sich ein System weiterentwickelt, ändert sich auch die Statusstruktur, daher schränkt Status in der URL die Evolution ein
Denn URLs sind im Grunde permanente Zeichenketten
Stattdessen sollte man die URL eher als eine Art Protokoll betrachten und den Status entsprechend kodieren und dekodieren
Bei einfachen Seiten kann man durchaus den gesamten Status in die URL legen
Bei Feeds hängt es jedoch von den Nutzererwartungen ab, etwa davon, ob ein Neuladen wieder den neuesten Zustand zeigen soll
Das URL-Längenlimit hängt von Browser-, Server-, CDN- und Suchmaschinen-Einstellungen ab, liegt aber meist unter 2000 Zeichen
Daher stellt sich die Frage, wie viel Status sich innerhalb dieser Grenze unterbringen lässt oder ob ein anderer Ansatz nötig ist
- . _ ~), daher ist die Informationsdichte ziemlich hochdraw.io kann den gesamten Status in der URL speichern und so teilbar machen
Die Diagrammdaten werden in Base64 kodiert, sodass eine vollständige Wiederherstellung über einen einzigen Link möglich ist
Ich bin mir nur nicht sicher, ob das wirklich unter die Definition eines „state container“ fällt
Ich verwende in selbstgehosteten Apps Hash-Routing (
#/dashboard)Dadurch braucht man keine serverseitigen URL-Rewrites (.htaccess usw.), was zwar nicht perfekt ist, aber die Einschränkungen der Deployment-Umgebung verringert
Das aktuelle Microsoft Teams behandelt alle Ansichten über eine einzige URL und ist daher nicht bookmarkbar
Man kann ein bestimmtes Team oder einen bestimmten Kanal nicht direkt öffnen, was extrem unpraktisch ist
HATEOAS bekommt wegen seines Namens nicht viel Aufmerksamkeit, ist aber letztlich ein Grundkonzept des Webs
In Umgebungen, in denen man Server und Client vollständig kontrolliert, erzeugt es jedoch nur zusätzliche Komplexität
Besonders wenn der Client die Struktur der Endpunkte trotzdem kennen muss, macht es URLs nur undurchsichtiger
Ich nutze die Tab-Energiesparfunktion sehr gern, aber bei Web-Apps, die einen fixierten URL haben und als ein Block funktionieren, gehen beim Wechsel in den Energiesparmodus Informationen verloren.
Andererseits sind genau solche Webseiten ausnahmslos so schwergewichtig, dass man den Energiesparmodus auch nicht einfach deaktivieren kann.