Herramientas de desarrollo · Codificador y decodificador de URL
escape() vs encodeURIComponent: cómo evolucionó la codificación de URL de JavaScript
· Antecedentes
javascript codificación de URL historial
JavaScript ha tenido tres generaciones de funciones de codificación de URL, y la más antigua aún se esconde en el código de producción. ¡Esta publicación explica qué hace mal escape(), por qué ES3 agregó las funciones URI y por qué las conservan! * '( ).
El %u20AC en un registro heredado: la huella inconfundible de escape() y el error de decodificación que provoca
Un archivo JavaScript heredado contiene una llamada de codificación URL que utiliza la función escape() obsoleta. La salida de un archivo de registro o mensaje de error incluye la secuencia %u20AC, una huella digital inconfundible de la función escape() obsoleta que nadie más utiliza. Esta secuencia no coincide con ninguna codificación de URL estándar y un decodificador basado en reglas RFC 3986 o WHATWG no la reconocerá. Los datos no pueden circular a través de herramientas modernas. Es un signo común de código anterior a ES3 y no se ha actualizado desde la década de 1990.
La función escape() fue diseñada en la era Netscape, antes de que JavaScript tuviera estándares o reglas formales de codificación de URL. Codifica la mayoría de los caracteres que no son ASCII usando la notación %uXXXX, un código hexadecimal de cuatro dígitos que nadie más usa y que ningún estándar define en ninguna parte. Esto tenía sentido para usos únicos dentro de un navegador, pero rompía la compatibilidad con los estándares de URL e hacía que los datos fueran imposibles de decodificar en otros lugares.
escape() y unescape(): un diseño de la era Netscape — Suposiciones latinas 1, la invención de %uXXXX y por qué nunca coincidió con ningún estándar
escape() y unescape() asumen que la entrada es Latin-1 (ISO 8859-1), la codificación de caracteres anterior a UTF-8 y Unicode. Convierten cada carácter a un código hexadecimal, usando %XX para caracteres latinos-1 de bits altos y %uXXXX para todo lo que no sea latino-1. Un carácter no latino-1 como un emoji no se puede representar en absoluto. Las funciones son simples y rápidas, pero también son completamente inadecuadas para cualquier caso de uso moderno.
Ambas funciones se agregaron a JavaScript antes de que existieran los estándares. Quedaron obsoletos inmediatamente después de que ES3 introdujo la codificación de URL adecuada en 1999. Permanecen en JavaScript por motivos de compatibilidad con versiones anteriores; eliminarlos rompería el código antiguo. Pero cualquier código nuevo nunca debería usarlos. Son una reliquia heredada.
ES3 (1999) agrega encodeURI y encodeURIComponent: UTF-8 codificación porcentual alineada con RFC 2396
ES3 introdujo dos funciones: encodeURI y encodeURIComponent. Ambos realizan UTF-8 porcentaje de codificación: convierten caracteres que no son ASCII en UTF-8 bytes y luego escriben cada byte como %HH. Ambos se alinean con RFC 2396, que estaba vigente en ese momento. RFC 3986 llegó más tarde y no cambió el comportamiento de codificación. Estas funciones siguen siendo el estándar hoy en día y deben utilizarse.
encodeURI está destinado a codificar un URI completo; encodeURIComponent está destinado a codificar un componente dentro de un URI, como un valor de consulta o un segmento de ruta. La diferencia es absolutamente crítica y fácil de malinterpretar. encodeURI conserva caracteres estructurales como: /? # @ = & y ;. encodeURIComponent los codifica todos, dejándolos seguros para incrustarlos dentro de un URI más grande.
¡Por qué! * ' ( ) aún permanecen sin codificar: los caracteres de 'marca' del RFC 2396 se congelaron en el idioma después de que el RFC 3986 los movió
Ambas funciones dejan estos caracteres sin codificar: letras, dígitos, guión (-), guión bajo (_), punto (.), tilde (~) y los cinco signos de puntuación. * '( ). Las marcas provienen del RFC 2396, que las enumera como caracteres de "marca" no reservados. RFC 3986 salió en 2005 y movió esos cinco a una categoría diferente, pero JavaScript ya había congelado encodeURI y encodeURIComponent en 1999. Cambiar qué caracteres dejan en paz rompería el código existente, por lo que se quedaron.
La decisión de mantener esas cinco marcas sin codificar para lograr compatibilidad con versiones anteriores significa que la codificación de JavaScript no coincide perfectamente ni con el RFC 3986 ni con el estándar WHATWG. Está lo suficientemente cerca para un uso práctico y cambiarlo ahora es completamente imposible. Esta es una lección sobre la estabilidad de la API: una vez que congelas el comportamiento, no puedes cambiarlo incluso si el estándar evoluciona.
Ejemplo resuelto: la misma cadena a través de escape, encodeURI y encodeURIComponent: tres salidas comparadas
Tome la cadena "I+D (investigación) = cafetería". Ejecútelo a través de escape(), encodeURI y encodeURIComponent. escape() produce "R%26D%20(research)%20%3D%20caf%E9's", mezclando paréntesis y apóstrofe sin codificar con ampersand e iguales codificados por porcentaje. encodeURI produce "R&D%20(research)%20=%20caf%C3%A9's", dejando el signo comercial y igual solo porque son estructurales. encodeURIComponent produce "R%26D%20%28research%29%20%3D%20caf%C3%A9%27s", codificando todo, incluidos los paréntesis y el apóstrofo.
Pegue la misma cadena en el codificador y decodificador de URL y cambie entre encodeURI y encodeURIComponent para ver la diferencia. Luego inspecciona lo que produciría escape() (puedes llamarlo en la consola del navegador, aunque te avisará). Verá inmediatamente que las tres funciones producen tres resultados completamente diferentes.
Migrar desde escape(): asignar llamadas antiguas a la función moderna correcta y manejar datos %uXXXX almacenados
El código antiguo que usa escape() debe actualizarse. Si se usó escape() para codificar un componente URI, reemplácelo con encodeURIComponent. Si se usó para codificar un URI completo, use encodeURI. Para los datos almacenados que contienen secuencias %uXXXX, necesita un decodificador personalizado: convierta cada %uXXXX en un punto de código Unicode y luego recopile los puntos de código en una cadena. El unescape() integrado de JavaScript leerá %uXXXX, pero es posible que el resultado no sea correcto UTF-8.
Después de reemplazar escape(), pruebe el código con cadenas que contengan caracteres no ASCII, puntuación y caracteres especiales. El resultado ahora debería coincidir con lo que esperan las herramientas y estándares modernos. Si su código es muy anterior a ES3, también podría utilizar otros patrones obsoletos; Una auditoría exhaustiva merece el esfuerzo.
Lo que esto no cubre: las API URL y URLSearchParams, que se tratan por separado
Las API URL y URLSearchParams, agregadas mucho más tarde, proporcionan interfaces de nivel superior para la construcción de URL y la codificación de componentes. Manejan todos los escapes automáticamente y coinciden exactamente con el estándar de URL WHATWG. Son la forma preferida de crear URL mediante programación en JavaScript moderno.
Esta publicación cubre solo las funciones de codificación, no las API de nivel superior. URL y URLSearchParams analizan la estructura, seleccionan las reglas de los componentes y serializan el resultado, mientras que encodeURIComponent transforma una cadena proporcionada sin saber dónde se colocará. Esa distinción es el límite: migre una antigua llamada escape() según si manejaba un valor o una dirección, luego considere reemplazar la concatenación manual circundante con las API estructuradas como una refactorización separada.
Conclusión: tres funciones, un par sobreviviente: cómo el codificador y decodificador de URL muestra el comportamiento moderno de encodeURI y encodeURIComponent uno al lado del otro
El desarrollo moderno de JavaScript debe usar encodeURI o encodeURIComponent, nunca escape(). Las funciones se estandarizaron en 1999 y no han cambiado desde entonces. Codifican caracteres no ASCII como UTF-8 bytes y manejan correctamente los caracteres reservados estándar. La herramienta de codificación y decodificación de URL implementa ambas funciones y le permite ver su comportamiento en paralelo, lo que facilita elegir la adecuada para su componente.
Si encuentra secuencias %u en registros antiguos o datos almacenados, son salidas de escape() y deben migrarse. La migración es sencilla una vez que identifica el patrón. El código moderno nunca debería producirlos.