En una frase
La codificación de URL, llamada oficialmente codificación por porcentaje (percent-encoding), es el proceso de traducir caracteres que tienen un significado especial o no son válidos dentro de una URL a un formato seguro y universalmente entendido para que puedan transmitirse sin causar confusión.
El problema que resuelve
En la sopa primordial de la web primitiva, la vida era simple. Las URLs —o más ampliamente, los URIs (Identificadores Uniformes de Recursos)— fueron diseñadas para ser una forma limpia y predecible de localizar un recurso. Los arquitectos, incluyendo a Sir Tim Berners-Lee, construyeron este sistema sobre la base de un conjunto de caracteres limitado: ASCII.
Esto funcionaba de maravilla, siempre y cuando solo necesitaras apuntar a http://example.com/reports/April.html. Pero, ¿qué pasa cuando las cosas se complican?
Considera la anatomía de una URL. Tiene partes: un esquema (http:), un host (example.com), una ruta (/search), y quizás una cadena de consulta (?q=dogs&cats). Ciertos caracteres son directores estructurales en esta obra. Los dos puntos (:) separan el esquema. La barra diagonal (/) separa segmentos de la ruta. El signo de interrogación (?) inicia los parámetros de la consulta. El ampersand (&) separa un parámetro del siguiente.
Aquí es donde empieza el lío. ¿Qué pasa si quieres buscar la cadena literal "C++ & C#"? Si simplemente lo metes de sopetón en una URL, obtienes .../search?q=C++ & C#. Un servidor web ve esto y se confunde por completo. Piensa que la consulta es para "C++ ", y luego ve un ampersand y espera otro par clave-valor, pero solo se encuentra con un solitario " C#". Caos. El significado original se pierde.
Además, algunos caracteres simplemente no están permitidos. Un espacio es un buscapleitos clásico. ¿Cuándo es un espacio parte de un nombre de archivo y cuándo es solo un error tipográfico que un navegador debería ignorar? ¿Y qué hay de los caracteres fuera del alfabeto inglés básico? ¡La web es global! ¿Cómo pones Currículum.pdf o 你好.html en una URL diseñada para ASCII?
La codificación por porcentaje resuelve toda esta clase de problemas. Proporciona una vía de escape, una forma de decir: "Oye, Sr. Servidor Web, el/los siguiente(s) caracter(es) no son estructurales. No los interpretes. Son datos literales". Es el traductor universal que garantiza que una URL signifique lo mismo en un navegador en Brasil que en un servidor en Berlín.
Cómo funciona por dentro
La "magia" detrás de la codificación por porcentaje es sorprendentemente simple. Es menos un truco de magia y más un sencillo cifrado por sustitución que todo el mundo ha acordado usar.
El elenco de caracteres: Reservados vs. No reservados
Primero, necesitas saber qué caracteres son aceptables y cuáles son problemáticos. Se dividen en algunos grupos.
| Tipo de Carácter | Caracteres | Cuándo codificar |
|---|---|---|
| No reservados | A-Z a-z 0-9 - _ . ~ |
Nunca. Son los VIP del mundo de las URLs. Siempre son seguros. |
| Reservados | : / ? # [ ] @ ! $ & ' ( ) * + , ; = |
A veces. Tienen un significado estructural especial. Si quieres usarlos por su significado (como / en una ruta), no los codificas. Si quieres usarlos como datos literales (como un & en una consulta de búsqueda), debes codificarlos. |
| Otros (Inseguros) | (espacio), `< > " % { } \ |
^` y todos los caracteres no ASCII |
La clave es el contexto. El carácter ? está bien si es el único ? que separa la ruta de la cadena de consulta. Pero si necesitas un signo de interrogación literal dentro del valor de un parámetro de consulta, debes codificarlo.
El truco de magia: Porcentaje + Hexadecimal
El proceso de codificación es un simple baile de tres pasos:
- Elige un carácter que necesites codificar. Usemos el ampersand
&. - Encuentra su valor en byte usando un juego de caracteres estándar. Para la web, este estándar es UTF-8. En UTF-8 (y su predecesor ASCII), el carácter
&se representa con el número decimal38. - Convierte ese número a hexadecimal de dos dígitos y anteponle un signo de porcentaje (
%). El decimal38es26en hexadecimal.
Entonces, & se convierte en %26.
Probemos con algunos más:
- Un espacio es el decimal
32, que es20en hexadecimal. Codificado:%20. - Un signo de interrogación (
?) es el decimal63, que es3Fen hexadecimal. Codificado:%3F. - El propio signo de porcentaje (
%) es el decimal37,25en hexadecimal. Así que para codificar un%literal, escribes%25.
Este sistema es brillante porque el signo de porcentaje en sí no es un carácter no reservado, por lo que un analizador (parser) sabe que cada vez que ve un %, debe esperar que le sigan dos dígitos hexadecimales.
¿Y qué pasa con los caracteres que no son del inglés?
Aquí es donde UTF-8 se vuelve crucial. Un carácter ASCII simple como A ocupa un byte. Pero un carácter como la é en francés o 好 en chino se representa con múltiples bytes en UTF-8. El proceso de codificación es el mismo, solo que se repite para cada byte.
Tomemos la é:
- En UTF-8,
ése representa con dos bytes:C3yA9(en hexadecimal). - Codifica cada byte por separado:
C3se convierte en%C3.A9se convierte en%A9.
- Combínalos:
ése convierte en%C3%A9.
El proceso de decodificación es exactamente el inverso. Un navegador o servidor ve %C3%A9, toma los dos bytes C3 y A9, los pasa por un decodificador UTF-8 y recupera el hermoso carácter é.
Historias del mundo real
La teoría es genial, pero veamos la práctica.
El caso de la consulta de búsqueda que desaparecía
Maya, una desarrolladora junior, estaba construyendo una función de búsqueda para un sitio de documentación técnica. Los usuarios podían buscar cosas como "C++", "promises & async/await", etc. Ella construía la URL de búsqueda simplemente concatenando cadenas de texto: site.com/search?q= + userInput.
Todo se fue al traste. Una búsqueda de promises & async/await generó la URL .../search?q=promises & async/await. El servidor, sin embargo, solo reportaba el término de búsqueda como "promises ". El & fue interpretado como un separador para un nuevo parámetro, async/await, que fue descartado porque no tenía una clave. Los resultados de su búsqueda eran completamente incorrectos.
La lección: Maya aprendió una regla de oro del desarrollo web: siempre codifica con porcentaje cualquier dato dinámico que se coloque en un componente de una URL. Después de que comenzó a codificar la entrada del usuario, la URL se convirtió correctamente en .../search?q=promises%20%26%20async%2Fawait. El servidor ahora recibía la cadena completa y correcta, y la búsqueda funcionaba a la perfección.
El incidente internacional
Una tienda online decidió destacar un nuevo producto de un socio alemán: el "Fußball". El equipo de marketing creó una URL amigable para él: store.com/products/Fußball. En sus navegadores modernos en la oficina, todo se veía bien.
Pero el día del lanzamiento fue un caos. Los tickets de soporte al cliente llovieron. Algunos usuarios recibían errores "404 No Encontrado". Otros veían una URL que se veía como .../products/Fu%C3%9Fball en la barra de su navegador, mientras que algunos veían .../products/FuÃball. El sistema era un mosaico de componentes nuevos y viejos, y no estaban manejando el carácter no ASCII ß (Eszett) de manera consistente. Algunas partes no lo codificaban, otras lo codificaban asumiendo UTF-8, y algunos sistemas heredados lo decodificaban asumiendo un juego de caracteres diferente, resultando en mojibake (texto basura).
La lección: Confiar en que los navegadores y servidores "simplemente manejen" los caracteres no ASCII en las URLs es una receta para la inconsistencia. Codificar por porcentaje de manera proactiva y consistente todos los caracteres no reservados usando el estándar UTF-8 asegura que tus URLs sean robustas y funcionen de manera predecible en todo el ecosistema web, tanto antiguo como nuevo.
El desastre de la doble codificación
Un equipo estaba construyendo un sistema de inicio de sesión único (SSO). El flujo funcionaba así: service-a.com redirigiría al usuario a sso.com/login, pasando su propia URL como parámetro para que el usuario pudiera ser enviado de vuelta después de iniciar sesión. La URL de redirección se veía así: sso.com/login?redirect_uri=https://service-a.com/dashboard?param=1.
El desarrollador en service-a.com fue inteligente y codificó el valor de redirect_uri, produciendo: sso.com/login?redirect_uri=https%3A%2F%2Fservice-a.com%2Fdashboard%3Fparam%3D1.
Sin embargo, el framework web que usaban tenía una capa de middleware que, "por seguridad", codificaba automáticamente todas las URLs de los parámetros de consulta salientes. Vio la cadena ya codificada y la codificó de nuevo. El % en %3A se convirtió en %25, por lo que %3A se convirtió en %253A. La URL final era un lío indescifrable de doble codificación. Cuando el usuario llegaba a sso.com, decodificaba la URL una vez y obtenía la cadena con una sola codificación, que no podía usar como redirección, rompiendo por completo el flujo de inicio de sesión.
La lección: Sé consciente de toda tu cadena de herramientas. Codifica los datos en el punto de creación y asegúrate de que ningún otro sistema más adelante los vuelva a codificar. La doble codificación es un bug común, de esos que te hacen rascarte la cabeza, que convierte una URL válida en basura inútil.
Errores y trampas comunes
- Codificar la URL completa. Nunca hagas esto. Si codificas con porcentaje
https://example.com, obtendrás algo comohttps%3A%2F%2Fexample.com. Esto ya no es una URL válida; las partes del esquema y la autoridad son ahora solo un revoltijo de caracteres sin sentido. Solo debes codificar los componentes individuales que lo necesitan (como los valores de los parámetros de consulta o segmentos específicos de la ruta). - No codificar en absoluto. El pecado más frecuente. Meter datos de usuario en bruto o datos con caracteres especiales directamente en una cadena de URL es buscarse agujeros de seguridad (como Cross-Site Scripting) y funcionalidades rotas.
- Olvidarse del contexto. El carácter
&está bien en la ruta de una URL, pero es un separador reservado en la cadena de consulta. Lo mismo ocurre con/. No necesitas codificar caracteres reservados cuando se usan para su propósito especial. - Confundir
+con%20. En el tipo de contenidoapplication/x-www-form-urlencoded(usado por formularios HTML), los espacios a menudo se codifican como un signo+en la cadena de consulta. Aunque muchos servidores entienden esto, la codificación por porcentaje oficial para un espacio es%20. Usar%20no es ambiguo y funciona correctamente en todas las partes de una URL, no solo en la cadena de consulta. Ante la duda, usa%20. - Usar un juego de caracteres obsoleto. La web funciona con UTF-8. Si codificas tus datos usando un juego de caracteres diferente (como ISO-8859-1), un servidor que espera UTF-8 malinterpretará los bytes y corromperá tus datos. Siempre especifica y usa UTF-8.
Por qué deberías tenerlo en tu radar
Si escribes código que toca una URL, necesitas entender la codificación por porcentaje. No es opcional. Deberías pensar en ello cada vez que estés:
- Construyendo una URL a partir de variables o entradas de usuario.
- Haciendo una solicitud a una API con parámetros en la URL.
- Manejando caracteres internacionales en nombres de archivo, perfiles de usuario o contenido que pueda aparecer en una URL.
- Analizando una URL en el lado del servidor para extraer datos.
- Escribiendo redirecciones o pasando URLs como parámetros a otros servicios.
En resumen, la codificación por porcentaje es una pieza fundamental de la fontanería de la web. Ignorarla conduce a software con bugs, inseguro y poco fiable. Saber cómo funciona es una marca de un desarrollador web profesional.
Para profundizar
- RFC 3986: La especificación canónica para Identificadores Uniformes de Recursos (URI). La Sección 2 define el conjunto de caracteres y las reglas de codificación por porcentaje. Es la fuente de verdad definitiva.
- MDN Web Docs: encodeURIComponent(): Una guía práctica para desarrolladores de JavaScript, que explica qué función usar y por qué. La sección "Ver también" enlaza a otras funciones de codificación relacionadas.
- Wikipedia: Percent-encoding: Una visión general completa y muy legible del concepto, su historia y sus diversos matices.
- W3C: Character encodings: Una introducción de alto nivel sobre por qué las codificaciones de caracteres son importantes en la web, con UTF-8 como el héroe de la historia.