Deutsch

Entwicklertools · URL-Encoder und -Decoder

escape() vs. encodeURIComponent: Wie sich die URL-Kodierung von JavaScript entwickelte

· Hintergrund

Javascript URL-Kodierung Geschichte

Drei Generationen von JavaScript-URL-Kodierungsfunktionen
Original-ToolAcre-Vektorillustration

JavaScript verfügt über drei Generationen von URL-Kodierungsfunktionen, und die ältesten lauern noch immer im Produktionscode. Dieser Beitrag erklärt, was escape() falsch macht, warum ES3 die URI-Funktionen hinzugefügt hat und warum sie erhalten bleiben! * ' ( ).

Der %u20AC in einem Legacy-Protokoll – der unverkennbare Fingerabdruck von escape() und der dadurch verursachte Dekodierungsfehler

Eine ältere JavaScript-Datei enthält einen URL-kodierenden Aufruf mit der veralteten Funktion escape(). Die Ausgabe in einer Protokolldatei oder Fehlermeldung enthält die Sequenz %u20AC – ein unverkennbarer Fingerabdruck der veralteten Funktion escape(), die sonst niemand verwendet. Diese Sequenz entspricht keiner Standard-URL-Codierung und ein Decoder, der auf RFC 3986- oder WHATWG-Regeln basiert, erkennt sie nicht. Die Daten können nicht durch moderne Tools übertragen werden. Dies ist ein häufiges Zeichen für Code, der älter als ES3 ist und seit den 1990er Jahren nicht mehr aktualisiert wurde.

Die Funktion escape() wurde in der Netscape-Ära entwickelt, bevor JavaScript Standards oder formale URL-Kodierungsregeln hatte. Es kodiert die meisten Nicht-ASCII-Zeichen mit der %uXXXX-Notation, einem vierstelligen Hexadezimalcode, den sonst niemand verwendet und den nirgendwo ein Standard definiert. Dies war für einmalige Verwendungen innerhalb eines Browsers sinnvoll, beeinträchtigte jedoch die Kompatibilität mit URL-Standards und machte es unmöglich, Daten anderswo zu dekodieren.

escape() und unescape(): ein Design aus der Netscape-Ära – Latin-1-Annahmen, die %uXXXX-Erfindung und warum sie nie einem Standard entsprach

escape() und unescape() gehen davon aus, dass die Eingabe Latin-1 (ISO 8859-1) ist, die Zeichenkodierung vor UTF-8 und Unicode. Sie konvertieren jedes Zeichen in einen Hexadezimalcode, wobei %XX für High-Bit-Latin-1-Zeichen und %uXXXX für alles außerhalb von Latin-1 verwendet wird. Ein Nicht-Latin-1-Zeichen wie ein Emoji kann überhaupt nicht dargestellt werden. Die Funktionen sind einfach und schnell, für jeden modernen Anwendungsfall aber auch völlig falsch.

Beide Funktionen wurden zu JavaScript hinzugefügt, bevor es Standards gab. Sie wurden sofort veraltet, nachdem ES3 in 1999 die richtige URL-Codierung eingeführt hatte. Sie bleiben aus Gründen der Abwärtskompatibilität in JavaScript – ihre Entfernung würde alten Code zerstören. Aber neuer Code sollte sie niemals verwenden. Sie sind ein Relikt aus der Vergangenheit.

ES3 (1999) fügt encodeURI und encodeURIComponent hinzu – UTF-8 Prozentkodierung ausgerichtet auf RFC 2396

ES3 hat zwei Funktionen eingeführt: encodeURI und encodeURIComponent. Beide führen eine UTF-8-Prozentkodierung durch: Konvertieren Sie Nicht-ASCII-Zeichen in UTF-8 Bytes und schreiben Sie dann jedes Byte als %HH. Beide richten sich nach dem damals aktuellen RFC 2396. RFC 3986 kam später und änderte das Codierungsverhalten nicht. Diese Funktionen sind auch heute noch Standard und sollten genutzt werden.

encodeURI ist für die Kodierung eines vollständigen URI gedacht; encodeURIComponent dient zum Codieren einer Komponente innerhalb eines URI, z. B. eines Abfragewerts oder eines Pfadsegments. Der Unterschied ist absolut entscheidend und kann leicht missverstanden werden. encodeURI bewahrt Strukturzeichen wie: /? # @ = & und ;. encodeURIComponent kodiert alle diese, sodass sie sicher in einen größeren URI eingebettet werden können.

Warum ! * ' ( ) bleiben immer noch uncodiert – die „Mark“-Zeichen von RFC 2396 sind in der Sprache eingefroren, nachdem RFC 3986 sie verschoben hat

Beide Funktionen lassen diese Zeichen uncodiert: Buchstaben, Ziffern, Bindestrich (-), Unterstrich (_), Punkt (.), Tilde (~) und die fünf Satzzeichen! * ' ( ). Die Markierungen stammen von RFC 2396, der sie als nicht reservierte „Mark“-Zeichen auflistete. RFC 3986 kam in 2005 heraus und verschob diese fünf in eine andere Kategorie, aber JavaScript hatte encodeURI und encodeURIComponent in 1999 bereits eingefroren. Eine Änderung der Zeichen, die sie in Ruhe ließen, würde den vorhandenen Code beschädigen, also blieben sie.

Die Entscheidung, diese fünf Markierungen aus Gründen der Abwärtskompatibilität unverschlüsselt zu belassen, bedeutet, dass die Kodierung von JavaScript weder RFC 3986 noch dem WHATWG-Standard perfekt entspricht. Es ist nah genug für den praktischen Gebrauch, und es ist völlig unmöglich, es jetzt zu ändern. Dies ist eine Lektion in Sachen API-Stabilität: Sobald Sie das Verhalten eingefroren haben, können Sie es nicht mehr ändern, selbst wenn sich der Standard weiterentwickelt.

Bearbeitetes Beispiel: derselbe String durch Escape, encodeURI und encodeURIComponent – ​​drei Ausgaben verglichen

Nehmen Sie die Zeichenfolge „R&D (Forschung) = Cafés“. Führen Sie es über escape(), encodeURI und encodeURIComponent aus. escape() erzeugt „R%26D%20(research)%20%3D%20caf%E9's“ und mischt uncodierte Klammern und Apostrophe mit prozentcodierten kaufmännischen Und-Zeichen und Gleichheitszeichen. encodeURI erzeugt „R&D%20(research)%20=%20caf%C3%A9's“ und lässt das kaufmännische Und und die Gleichheitszeichen allein, da sie strukturell sind. encodeURIComponent erzeugt „R%26D%20%28research%29%20%3D%20caf%C3%A9%27s“ und kodiert alles, einschließlich der Klammern und des Apostrophs.

Fügen Sie dieselbe Zeichenfolge in den URL-Encoder und -Decoder ein und wechseln Sie zwischen encodeURI und encodeURIComponent, um den Unterschied zu sehen. Überprüfen Sie dann, was escape() erzeugen würde (Sie können es in der Browserkonsole aufrufen, erhalten jedoch eine Warnung). Sie sehen sofort, dass die drei Funktionen drei völlig unterschiedliche Ergebnisse liefern.

Migration weg von escape() – Zuordnung alter Aufrufe zur richtigen modernen Funktion und Handhabung gespeicherter %uXXXX-Daten

Alter Code, der escape() verwendet, muss aktualisiert werden. Wenn escape() zum Codieren einer URI-Komponente verwendet wurde, ersetzen Sie es durch encodeURIComponent. Wenn es zum Codieren eines vollständigen URI verwendet wurde, verwenden Sie encodeURI. Für gespeicherte Daten, die %uXXXX-Sequenzen enthalten, benötigen Sie einen benutzerdefinierten Decoder: Konvertieren Sie jeden %uXXXX in einen Unicode-Codepunkt und sammeln Sie dann die Codepunkte in einer Zeichenfolge. Das in JavaScript integrierte unescape() liest %uXXXX, aber das Ergebnis ist möglicherweise nicht korrekt UTF-8.

Testen Sie nach dem Ersetzen von escape() den Code mit Zeichenfolgen, die Nicht-ASCII-Zeichen, Satzzeichen und Sonderzeichen enthalten. Die Ausgabe sollte nun den Erwartungen moderner Tools und Standards entsprechen. Wenn Ihr Code deutlich älter als ES3 ist, verwendet er möglicherweise auch andere veraltete Muster. Ein umfassendes Audit lohnt sich.

Was hiervon nicht abgedeckt wird – die URL- und URLSearchParams-APIs, die separat behandelt werden

Die viel später hinzugefügten URL- und URLSearchParams-APIs bieten übergeordnete Schnittstellen für die URL-Konstruktion und Komponentenkodierung. Sie verarbeiten alle Escapezeichen automatisch und entsprechen genau dem WHATWG-URL-Standard. Sie sind die bevorzugte Methode zum programmgesteuerten Erstellen von URLs in modernem JavaScript.

Dieser Beitrag behandelt nur die Codierungsfunktionen, nicht die APIs höherer Ebenen. URL und URLSearchParams analysieren die Struktur, wählen Komponentenregeln aus und serialisieren das Ergebnis, während encodeURIComponent eine bereitgestellte Zeichenfolge transformiert, ohne zu wissen, wo sie platziert wird. Diese Unterscheidung ist die Grenze: Migrieren Sie einen alten escape()-Aufruf danach, ob er einen Wert oder eine Adresse verarbeitet hat, und erwägen Sie dann, die umgebende manuelle Verkettung durch die strukturierten APIs als separaten Refaktor zu ersetzen.

Takeaway: drei Funktionen, ein überlebendes Paar – wie der URL-Encoder und -Decoder das moderne Verhalten von encodeURI und encodeURIComponent nebeneinander zeigt

Moderne JavaScript-Entwicklung sollte encodeURI oder encodeURIComponent verwenden, niemals escape(). Die Funktionen wurden in 1999 standardisiert und haben sich seitdem nicht geändert. Sie kodieren Nicht-ASCII-Zeichen als UTF-8 Bytes und verarbeiten standardmäßig reservierte Zeichen korrekt. Das URL-Encoder- und Decoder-Tool implementiert beide Funktionen und lässt Sie deren Verhalten nebeneinander sehen, sodass Sie ganz einfach die richtige für Ihre Komponente auswählen können.

Wenn Sie in alten Protokollen oder gespeicherten Daten auf %u-Sequenzen stoßen, sind diese Escape()-Ausgaben und sollten migriert werden. Die Migration ist unkompliziert, sobald Sie das Muster identifiziert haben. Moderner Code sollte sie niemals erzeugen.