Skip to content

Guide

URL-Encoding erklärt: Prozent-Kodierung, Query-Strings und die Tücken

Die Hälfte aller Fehler beim Umgang mit URLs entsteht dadurch, dass man das Falsche kodiert – oder es doppelt kodiert.

By Published

URL-Encoding ist eines jener Themen, die trivial wirken, bis die Produktion bei jeder Suche mit einem französischen Akzent 400 Bad Request zurückgibt. Die Regeln sind einfach, aber über vier Spezifikationen verteilt, die nicht ganz übereinstimmen, und die JavaScript-Helfer tragen Namen, die aktiv in die Irre führen. Dieser Ratgeber bündelt die Regeln an einem Ort und markiert die Stellen, an denen die Standards still uneins sind.

Was „URL-Encoding“ tatsächlich bedeutet

URLs sind auf eine kleine Teilmenge von ASCII beschränkt. Jedes Zeichen außerhalb dieser Menge – oder jedes Zeichen mit einer strukturellen Bedeutung, die der Parser sonst interpretieren würde – muss als ein oder mehrere Bytes mit einem vorangestellten % dargestellt werden. Das ist die Prozent-Kodierung, und die Regeln dazu, was kodiert wird, stammen aus RFC 3986. Sie können alle Beispiele unten mit unserem URL-Encoder ausprobieren.

RFC 3986 teilt Zeichen in drei Gruppen. Die nicht reservierte Menge ist A-Z a-z 0-9 - . _ ~; diese sind immer sicher und müssen nie kodiert werden. Die reservierte Menge (: / ? # [ ] @ ! $ & ' ( ) * + , ; =) trägt in einem Teil der URL eine strukturelle Bedeutung; kodieren Sie sie, wenn Sie das wörtliche Zeichen meinen, lassen Sie sie unangetastet, wenn Sie das Trennzeichen meinen. Alles andere – inklusive Leerzeichen, ", <, >,{ und alles Nicht-ASCII – muss prozent-kodiert werden.

Wo jedes Zeichen kodiert werden muss

Dasselbe Byte muss je nachdem, in welcher Komponente der URL es auftritt, kodiert werden oder nicht. Ein Pfadsegment erlaubt : und @ unkodiert; ein Query-Wert muss / oder ? nicht kodieren (weil der Parser bei # stoppt); ein Fragment ist die nachsichtigste Komponente überhaupt. In der Praxis ignorieren fast alle diese Unterschiede und kodieren alles außerhalb der nicht reservierten Menge, sobald sie einen Wert in eine URL einsetzen. Das ist konservativ und korrekt.

Die eine Stelle, an der das zählt: Kodieren Sie nicht die /-Zeichen, die Ihre Pfadsegmente trennen. Kodieren Sie jedes Segment und verbinden Sie dann mit /. Kodieren Sie den Schrägstrich ebenfalls, erhalten Sie %2F im Pfad, was die meisten Server aus Sicherheitsgründen ablehnen (es würde Angreifern sonst erlauben, ..-Sequenzen an Verzeichnis-Wächtern vorbeizuschmuggeln).

encodeURI vs. encodeURIComponent in JavaScript

JavaScript bringt zwei Encoder mit, und der Unterschied zwischen ihnen ist die Quelle enorm viel verschwendeter Debugging-Zeit.

  • encodeURI(value) nimmt an, value sei bereits eine vollständige URL. Es lässt die reservierten Zeichen (; / ? : @ & = + $ , #) unangetastet, damit die URL parsbar bleibt. Es kodiert Leerzeichen, Akzente und die kleine Menge an Zeichen, die nirgendwo in einer URL erlaubt sind.
  • encodeURIComponent(value) nimmt an, value sei eine einzelne Komponente, die in eine URL eingesetzt wird – meist ein Pfadsegment oder ein Query-Wert. Es kodiert alles außer der nicht reservierten Menge plus ! ' ( ) *.

Die Faustregel: Wenn Sie eine URL durch Verkettung bauen, verwenden Sie encodeURIComponent auf jeden eingesetzten Wert. Wenn Sie eine bereits gebaute URL normalisieren, ist encodeURI das richtige Werkzeug. Es gibt fast keinen Fall, in dem Sie beide anwenden wollen.

Formulardaten: die +/Leerzeichen-Ausnahme

HTML-Formularübermittlungen kodieren mit dem Medientyp application/x-www-form-urlencoded, definiert im WHATWG-URL-Standard. Dieses Format weicht in zwei Punkten von RFC 3986 ab. Erstens werden Leerzeichen zu +statt %20. Zweitens wird ein wörtliches + im Wert als %2B kodiert, damit der Dekodierer sie auseinanderhalten kann.

Sowohl %20 als auch + dekodieren in der Praxis zu einem Leerzeichen – jeder verbreitete serverseitige Parser akzeptiert beides in einem Query-String. Aber Sender sollten konsistent sein. Verwenden Sie + in Formular-Bodys und in Query-Strings, die Formular-Bodys nachahmen; verwenden Sie %20sonst überall, besonders in Pfadsegmenten, wo +ein wörtliches Pluszeichen ist.

Verschachtelte Arrays und Objekte: es gibt keinen Standard

Query-Strings wurden für flache key=value-Paare entworfen. Verschachtelte Datenstrukturen müssen abgeflacht werden, und die Abflachungsregel ist eine Entscheidung pro Framework. Die vier weit verbreiteten Konventionen:

  1. Wiederholte Schlüssel. ?tag=js&tag=ts wird auf dem Server zu einem Array. Die einfachste Konvention; Standard in Express, Gos net/url und den meisten Node-Parsern.
  2. PHP-Stil-Klammern. ?tag[]=js&tag[]=ts für Arrays; ?user[name]=alex für verschachtelte Objekte. Die Klammern müssen selbst prozent-kodiert werden (%5B / %5D), um streng standardkonform zu sein, obwohl die meisten Server die rohe Form akzeptieren.
  3. Rails-Punkt-Notation. ?user.name=alex&user.age=30. Heute weniger verbreitet; tritt in einigen älteren Ruby- und .NET-APIs auf.
  4. Kommagetrennt. ?tag=js,ts. Verbreitet in REST-APIs (OpenAPI listet dies als form/explode=false-Stil). Knapp, aber mehrdeutig, wenn Werte selbst Kommas enthalten können.

Wählen Sie eine Konvention pro API und dokumentieren Sie sie. Die schmerzhaftesten Fehler in diesem Bereich entstehen, wenn ein Client, der Klammern ausgibt, mit einem Server spricht, der wiederholte Schlüssel erwartet – beide scheinen zu funktionieren, aber einer behält stillschweigend nur den letzten Wert.

CJK, Emoji und anderes Nicht-ASCII

Jedes Zeichen außerhalb von ASCII muss als seine UTF-8-Bytes kodiert werden, dann Byte für Byte prozent-kodiert. Das Zeichen (U+5317) sind die drei Bytes E5 8C 97 in UTF-8, die in einer URL zu %E5%8C%97 werden. Emoji folgen derselben Regel: 🔥 (U+1F525) sind die vier Bytes F0 9F 94 A5, kodiert als %F0%9F%94%A5.

Legacy-Systeme geben dasselbe Zeichen manchmal in einer anderen Kodierung aus – GBK für Chinesisch, Shift-JIS für Japanisch, Windows-1251 für Kyrillisch. Wenn Sie ein Backend von vor 2010 anbinden und Ihr dekodierter Text als Müll herauskommt, versuchen Sie, die Bytes als Windows-1252 oder die landestypische Kodierung zu interpretieren, bevor Sie annehmen, die URL sei defekt.

Internationalisierte Domainnamen

Hostnamen folgen einer anderen Regel. Nicht-ASCII-Hostnamen werden als Punycode (RFC 3492) kodiert, nicht prozent-kodiert. Die Domain 例え.jp wird in der tatsächlichen DNS-Abfrage zu xn--r8jz45g.jp. Browser zeigen die Unicode-Form für erkannte Schriften an, übertragen aber die Punycode-Form auf der Leitung. Wenn Sie eine URL mit einem Nicht-ASCII-Host bauen, konvertieren Sie den Host mit einem Punycode-Encoder, nicht mit dem URL-Encoder.

Häufige Tücken

  • Doppelte Kodierung. Einen Wert zu kodieren und das Ergebnis dann durch einen weiteren Encoder zu schicken, erzeugt %2520 statt %20. Verfolgen Sie jeden Kodierungsschritt explizit; kodieren Sie niemals „nur zur Sicherheit“ einen Wert, den Sie nicht selbst erzeugt haben.
  • Hash-Fragmente sind nur clientseitig. Alles nach # wird nie an den Server gesendet. Status im Fragment abzulegen ist eine bewusste Entscheidung (Datenschutz, Single-Page-App-Routing); ihn dort versehentlich abzulegen verbirgt Fehler, bis der Server beginnt, sich darauf zu verlassen.
  • Pluszeichen in mailto-Links. mailto:[email protected] funktioniert, weil mailto-URLs RFC-3986-Regeln nutzen, nicht Formular-Kodierung. Bauen Sie mailto-Links von Hand, nicht mit einem Formular-Encoder.
  • Die nicht reservierte Menge schloss die Tilde historisch aus. RFC 2396 (der Vorgänger von 3986) behandelte ~als reserviert. Ältere Encoder geben weiterhin %7E aus; der moderne Standard betrachtet es als nicht reserviert. Beide dekodieren gleich.
  • Längenbeschränkungen sind real. Die meisten Server begrenzen URLs auf 8 KB. Browser variieren von 2 KB (älterer IE) bis 32 KB (modernes Chrome). Wenn Ihr Query-String diesen Bereich erreicht, verschieben Sie die Nutzlast in einen POST-Body.

Ein praktischer Arbeitsablauf

Beim Bauen von URLs im Code: Konstruieren Sie ein Objekt, das die Komponenten darstellt (Schema, Host, Pfadsegmente, Query-Map), und serialisieren Sie dann einmal mit einer Bibliothek, der Sie vertrauen – URL und URLSearchParams in Browsern, die Entsprechungen in jeder anderen großen Sprache. Von Hand zusammengesetzte URLs sind die Fehlerquelle.

Denken Sie daran, dass die kodierte URL nur die Anforderungszeile ist; dieselbe HTTP-Schicht trägt Header, die Ihr Code selten manuell escaped, aber dennoch mit Sorgfalt behandeln sollte. Der Referer-Header verrät die vorherige URL (samt Query-String) an den nächsten Host, sofern Sie ihn nicht mit einer Referrer-Policy entfernen, der User-Agent-String lässt Server das Verhalten je Client variieren, und die verbindende IP-Adresse kommt in der TCP-Schicht an oder – hinter einem Proxy – in einem X-Forwarded-For-Header. Alles, was Sie in den Query-String legen, ist für alle drei sichtbar.

Beim Debuggen einer kodierten URL, die Ihnen jemand geschickt hat, fügen Sie sie in unseren URL-Encoder/Decoder ein und schalten die Richtung um. Das Tool dekodiert einmal pro Klick; wenn Sie also zweimal klicken müssen, um lesbaren Text zu erhalten, haben Sie eine doppelte Kodierung weiter oben bestätigt.

Das ehrliche Fazit

Verwenden Sie encodeURIComponent auf jeden eingesetzten Wert, niemals auf eine vollständige URL. Passen Sie Ihre Formular-Kodierung (Leerzeichen-als-Plus) an Ihren Transportkontext an. Wählen Sie eine Array-Konvention pro API und dokumentieren Sie sie. Vertrauen Sie UTF-8. Und wenn etwas doppelt kodiert aussieht, ist es das fast sicher – verfolgen Sie den zweiten Encoder, statt es mit einem Dekodierdurchlauf zu übertünchen.

Frequently asked questions

Soll ich die gesamte URL oder nur Teile davon kodieren?
Kodieren Sie nur die Teile, die Sie kontrollieren – Pfadsegmente und Query-Werte. Kodieren Sie niemals eine ganze URL mit encodeURIComponent, denn es zerstört den Schema-Trenner (`://`) und die Trennzeichen `?` und `&`. Kodieren Sie jedes Pfadsegment und jeden Query-Wert unabhängig und setzen Sie sie anschließend zusammen.
Warum zeigt meine URL + statt %20 für Leerzeichen?
Das ist das Verhalten von `application/x-www-form-urlencoded`, das bei HTML-Formularübermittlungen verwendet wird. In diesem Medientyp wird ein Leerzeichen als `+` kodiert und ein wörtliches `+` als `%2B`. In RFC-3986-URL-Pfaden sind Leerzeichen immer `%20`. Server dekodieren meist beides, aber wenn Sie eine URL von Hand bauen, bevorzugen Sie `%20` überall außer in Formular-Bodys.
Ist encodeURI() in JavaScript je die richtige Wahl?
Selten. `encodeURI()` lässt reservierte Zeichen wie `?`, `#`, `&` und `/` unangetastet, weil es annimmt, Sie kodierten eine vollständige URL. Das ist fast nie das, was Sie tatsächlich wollen – meist wollen Sie einen Wert kodieren, der in eine URL eingesetzt wird, was die Aufgabe von `encodeURIComponent` ist. Verwenden Sie `encodeURI` nur, wenn Sie eine wörtlich vom Nutzer getippte URL mit Nicht-ASCII-Zeichen bereinigen.
Wie werden CJK-Zeichen kodiert?
RFC 3986 verlangt UTF-8, gefolgt von einer Prozent-Kodierung jedes Bytes. Das Zeichen `日` (U+65E5) ist `E6 97 A5` in UTF-8, also kodiert es sich zu `%E6%97%A5`. Ältere Systeme nutzten manchmal GBK- oder Shift-JIS-Bytes, weshalb beim Scrapen alter CJK-Seiten gelegentlich `%C8%D5` für dasselbe Zeichen auftaucht. Moderne Browser geben immer UTF-8 aus.
Wie kodiere ich Arrays in Query-Strings?
Es gibt keinen einheitlichen Standard. PHP und Rails verwenden Klammer-Notation (`tags[]=a&tags[]=b`); Express und die meisten Node-Frameworks akzeptieren entweder Klammern oder wiederholte Schlüssel (`tags=a&tags=b`); manche APIs verlangen kommagetrennt (`tags=a,b`). Prüfen Sie den Parser des Konsumenten, bevor Sie eine Konvention wählen, und dokumentieren Sie die Wahl in Ihrer API-Referenz, damit Clients nicht raten müssen.
Warum bekomme ich doppelt kodierte Werte wie %2520?
Etwas hat den Wert kodiert, dann hat etwas anderes das Ergebnis erneut kodiert. `%20` (ein kodiertes Leerzeichen) wurde zu `%2520`, weil das `%` erneut als `%25` kodiert wurde. Die Lösung ist, den zweiten Kodierungsschritt zu finden und zu entfernen – niemals dekodieren-dann-erneut-kodieren als Behelf, denn Sie verlieren Informationen für Werte, die vor jeder Kodierung legitim ein `%25` enthielten.

Sources & references

Authoritative references cited by this piece. Verified by Buğra Sözeri on the dates shown and re-checked at every deploy.

  • RFC 3986 — Uniform Resource Identifier (URI): Generic SyntaxDie maßgebliche Spezifikation für die URI-Syntax, einschließlich der reservierten/nicht reservierten Zeichensätze und der in diesem Ratgeber durchgängig referenzierten Prozent-Kodierungsregeln(as of )
  • WHATWG URL StandardDer lebende Standard, den Browser tatsächlich umsetzen; löst RFC 3986 für das Browser-Verhalten ab und definiert den application/x-www-form-urlencoded-Serializer(as of )
  • MDN — encodeURIComponent()Referenz für die JavaScript-Kodierungsfunktionen und den genauen Zeichensatz, den jede bewahrt(as of )
  • RFC 1738 — Uniform Resource LocatorsHistorischer Kontext für die Formular-Kodierungs-`+`-Konvention, die RFC 3986 vorausgeht(as of )

Related

Published May 31, 2026