Desarrollo

Qué es la codificación de URL y por qué tus enlaces se rompen

El percent-encoding en términos simples: qué caracteres hay que escapar, cuáles nunca, y las tres formas en que sale mal.

La codificación de URL —percent-encoding, para usar su nombre real— reescribe cualquier carácter que no pueda aparecer literalmente en una URL como un signo de porcentaje seguido de los dos dígitos hexadecimales de su byte. Un espacio se convierte en %20, el símbolo de número en %23 y é en %C3%A9. Existe porque una URL solo puede contener un conjunto pequeño de caracteres ASCII, y varios de esos caracteres ya están haciendo un trabajo estructural: el ? que abre una query string no puede ser al mismo tiempo un signo de interrogación dentro del término de búsqueda de alguien.

Ese es todo el mecanismo. Casi todo lo que sale mal con él viene de uno de tres errores: escapar la cantidad equivocada, escapar dos veces, o escapar caracteres cuando deberías estar escapando bytes.

¿Qué caracteres necesitan codificarse de verdad?

El RFC 3986, la especificación de 2005 que define la sintaxis de las URL, ordena cada carácter en tres grupos.

El grupo del medio es donde viven los bugs. Fíjate en ?q=fish&chips. Querías buscar "fish&chips"; el servidor lee un parámetro q con el valor fish, más un segundo parámetro llamado chips sin valor. Tus datos se cortaron en silencio en el ampersand y nada dio error. Codificado como corresponde, el valor es fish%26chips y llega entero.

La misma trampa atrapa al # (todo lo que va después se trata como un fragmento y nunca llega al servidor), a la / dentro de un segmento de la ruta y al = dentro del valor de un parámetro. Si quieres ver en qué se convierte un string, el codificador de URL de aquí te muestra los escapes mientras escribes, y si pegas una query string entera la divide en una tabla de parámetros para que puedas revisar cuáles valores sobrevivieron.

Por qué una sola letra acentuada se convierte en dos escapes

El percent-encoding opera sobre bytes, no sobre caracteres. El texto se convierte primero a UTF-8 y después cada byte que queda fuera del conjunto seguro se escribe como su propio escape.

é es un carácter pero dos bytes en UTF-8, así que se convierte en %C3%A9. Un emoji típico son cuatro bytes, así que se convierte en cuatro escapes: doce caracteres en pantalla para un solo glifo. Los caracteres chinos y japoneses son tres bytes cada uno, y por eso una URL con un término de búsqueda en chino se ve absurdamente larga.

También es un diagnóstico rápido. Si algo te devuelve %E9 para é, está codificando en Latin-1 en lugar de UTF-8, y va a arruinar cualquier cosa fuera del texto de Europa occidental. Los navegadores modernos y las bibliotecas estándar usan todos UTF-8; un %E9 suelto significa código viejo o una mala configuración en algún punto más arriba.

¿encodeURI o encodeURIComponent?

JavaScript trae dos funciones para esto, y no son intercambiables. La distinción es si estás codificando un valor o una dirección entera.

encodeURIComponent escapa también los caracteres estructurales. Úsalo para el valor de un parámetro, un segmento de la ruta, un pedazo de input del usuario. Córrelo sobre una dirección completa y obtienes https%3A%2F%2Fexample.com: técnicamente correcto, completamente inútil como enlace.

encodeURI deja la estructura intacta y solo escapa lo que nunca puede aparecer en crudo, como los espacios y las letras acentuadas. Sirve para reparar una dirección que alguien escribió mal. Nunca lo uses sobre input del usuario que estás por insertar en una URL: deja el & en paz, que es justamente el carácter que le permite a un valor escaparse de su propio parámetro.

La regla que cubre casi todos los casos: si estás pegando algo dentro de una URL que estás armando, quieres la versión component.

¿Un espacio es %20 o un signo más?

Los dos, según quién haya producido el string, y esto es genuinamente ambiguo en lugar de ser un caso de una convención equivocada.

El formato application/x-www-form-urlencoded —lo que manda un formulario HTML, y por lo tanto a lo que se parece la mayoría de las query strings— escribe un espacio como +. El RFC 3986, que rige las URL en general, lo escribe como %20 y trata al + como un signo más literal. Una query string no lleva ninguna marca que te diga cuál de las dos reglas la produjo.

La consecuencia práctica son los números de teléfono. ?tel=+44123 le llega a un montón de servidores como " 44123", con un espacio al principio donde estaba el código de país. Si un valor puede contener un más, codifícalo como %2B y deja de depender de cualquiera de las dos convenciones. %20 se entiende en todos lados, así que prefiérelo cuando puedas elegir.

Esto también limita a cualquier herramienta que lea una query string de vuelta, incluida la de aquí. Su tabla de parámetros decodifica + como un espacio, porque es el caso más común, así que un valor donde el más era literal se muestra mal. Nada en el string permite distinguir los dos casos, así que ninguna herramienta puede acertarle siempre.

Qué pasa cuando algo se codifica dos veces

Codifica un string, después codifica el resultado, y %20 se convierte en %2520, porque la segunda pasada escapa el propio signo de porcentaje como %25. El síntoma visible es una página que le muestra Rue%20de%20la%20Paix a un usuario, o una redirección que aterriza en un 404 con los escapes todavía en la ruta.

Suele pasar cuando dos capas hacen cada una su trabajo: tu código codifica un valor y después un framework o un helper de redirección codifica la URL entera otra vez a la salida. Decodifica una vez y mira qué obtienes. Si todavía hay escapes, decodifica de nuevo: los escapes que sobran en la salida decodificada son la señal.

Lo que ninguna herramienta puede hacer es decirte si la doble codificación fue un error. Una URL que legítimamente contiene el texto 100% lo guarda como 100%25, y eso es indistinguible de un accidente. Una vez que los datos doblemente codificados se escribieron en una base de datos, la ambigüedad es permanente, y por eso el arreglo va en el punto de la codificación y no en un script de limpieza.

¿La codificación de URL es cifrado, o lo mismo que Base64?

El percent-encoding no esconde nada. Es una convención de transporte, reversible por cualquiera con un teclado, y una query string es uno de los lugares menos privados para poner datos: termina en los logs de acceso del servidor, en el historial del navegador y, históricamente, en el header Referer que se manda al sitio siguiente. Los tokens, las contraseñas y los datos personales no van en una URL, por más cuidadosamente que los escapes.

También es algo distinto de Base64, aunque los dos aparezcan juntos seguido. Base64 convierte binario en texto; el percent-encoding hace que el texto sea seguro para una URL. El alfabeto estándar de Base64 incluye + y /, que necesitan escaparse en una URL, y por eso exactamente el RFC 4648 define una variante base64url que usa - y _ en su lugar.

Y no se aplica a los nombres de host. Un dominio como müller.de se convierte con punycode en xn--mller-kva.de, un algoritmo completamente aparte. Los percent-escapes no son válidos en un hostname, directamente.

¿Dónde sigue dando problemas el percent-encoding?

La forma más rápida de zanjar una discusión sobre una URL escapada es pegarla en el codificador y decodificador de URL y mirar: marca la entrada doblemente codificada, cuenta los escapes y parte una query string en sus parámetros con cada valor decodificado. Corre en tu navegador, y eso importa cuando la URL que estás depurando tiene un token de sesión adentro.

Si la URL va dentro de un href y no en la barra del navegador, necesita dos escapes, no uno: percent-encoding del valor para la URL y después escapar el resultado para el HTML que lo rodea. Las reglas de las entidades HTML son la mitad que este posteo no cubre, y hacerlas en el orden equivocado rompe el enlace tan a fondo como saltarse uno.

Preguntas frecuentes

¿Qué es la codificación de URL?

La codificación de URL, o percent-encoding, reemplaza los caracteres que no pueden aparecer literales en una URL por un signo de porcentaje y los dos dígitos hexadecimales de su byte. Un espacio se convierte en %20 y un ampersand en %26. Existe para que los datos puedan viajar dentro de una URL sin que se los confunda con la puntuación que le da su estructura.

¿Qué significa %20 en una URL?

Es un espacio. El número hexadecimal 20 es el valor del byte del carácter de espacio en ASCII, y un espacio en crudo no está permitido en una URL. También vas a ver espacios escritos como un signo más, que es la convención que usan los envíos de formularios HTML.

¿Qué caracteres hay que codificar en una URL?

Las letras, los dígitos y las cuatro marcas - . _ ~ nunca necesitan codificarse. Todo lo que está fuera de ASCII siempre lo necesita. La puntuación del medio — / ? # & = + y el resto — necesita codificarse cuando está dentro de un valor en lugar de funcionar como estructura.

¿La codificación de URL es lo mismo que el cifrado?

No. El percent-encoding es una convención pública y reversible, sin clave y sin secreto; cualquiera lo decodifica al instante. Las query strings además terminan en los logs del servidor y en el historial del navegador, así que los valores sensibles no deberían ir nunca en una URL.

¿Cómo decodifico una URL llena de signos de porcentaje?

Pégala en un decodificador y lee el resultado. Si la salida decodificada todavía tiene percent-escapes, se codificó dos veces y necesita una segunda pasada. Si el decodificador informa UTF-8 inválido, lo que produjo la URL usó otro conjunto de caracteres, normalmente Latin-1.

Última actualización 19 de septiembre de 2026