Seguro te ha pasado — una URL con espacios o caracteres especiales rompió algo. Quizás una búsqueda con & causó un comportamiento raro. O viste %20 en una URL y te preguntaste qué era eso. Vamos a aclarar todo esto.

Por qué las URLs necesitan codificación

Las URLs solo pueden contener un conjunto limitado de caracteres. La especificación RFC 3986 define los caracteres "no reservados" que siempre son seguros: A-Z, a-z, 0-9, -, _, . y ~. Todo lo demás — espacios, &, =, ?, caracteres no ASCII como ñ o 日本語 — debe codificarse con porcentaje.

Cómo funciona la codificación por porcentaje

Es sencillo: toma el valor en bytes UTF-8 del carácter y representa cada byte como % seguido de dos dígitos hexadecimales.

Ejemplos:

  • Espacio → %20
  • &%26
  • =%3D
  • é%C3%A9 (dos bytes en UTF-8)
  • %E6%97%A5 (tres bytes en UTF-8)

Así que Hello World se convierte en Hello%20World en la ruta de una URL.

El bug #1: Doble codificación

Este es el error de codificación URL más común que veo, y es sutil. Codificas un string, luego lo pasas a una función que lo codifica de nuevo. Ahora %20 (un espacio ya codificado) se convierte en %2520 porque el propio % se codifica.

Ejemplo del problema:

javascript

La solución: codificar los valores una sola vez, en el nivel correcto. No codifiques cosas que ya están codificadas.

Signo más vs. %20 — Sí, es confuso

En los query strings, los espacios pueden ser + o %20. La convención del + viene de la codificación de formularios HTML (application/x-www-form-urlencoded). En las rutas URL, solo %20 es válido.

Así que https://example.com/hello world → la ruta se codifica como https://example.com/hello%20world

Pero https://example.com/search?q=hello world → el query puede ser ?q=hello+world o ?q=hello%20world

encodeURI vs. encodeURIComponent

JavaScript te da dos funciones, y usar la incorrecta es un error clásico:

  • encodeURI() — Codifica una URL completa. Deja intactos :, /, ?, #, &, = porque son partes estructurales de la URL.
  • encodeURIComponent() — Codifica un componente de URL (como el valor de un parámetro de consulta). SÍ codifica :, /, ?, #, &, = porque podrían ser parte de los datos.

Regla general: usa encodeURIComponent() para valores, nunca para URLs completas. La documentación de MDN explica la diferencia perfectamente.

Otros lenguajes

  • Python: urllib.parse.quote() para rutas, urllib.parse.urlencode() para query strings — documentación aquí
  • Java: URLEncoder.encode() (usa + para espacios — ¡cuidado!)
  • PHP: urlencode() para query strings, rawurlencode() para rutas

Consejos rápidos

  • Siempre codifica los valores de los parámetros, no URLs completas
  • Decodifica una sola vez en el lado receptor — no pases valores codificados a través de múltiples capas
  • Prueba con casos extremos: espacios, &, =, #, caracteres no ASCII y emoji

Construyendo URLs de forma segura en JavaScript

La forma correcta de construir URLs con parámetros de consulta es usar las APIs integradas URL y URLSearchParams. Ellas manejan toda la codificación por ti:

javascript

Observa cómo URLSearchParams usa + para espacios (convención de codificación de formularios HTML) y codifica correctamente el & en el valor para que no se confunda con el & que separa parámetros. Esto es mucho más seguro que la concatenación de strings.

Errores comunes de codificación URL

1. Codificar toda la URL en lugar de solo los valores. Si ejecutas encodeURIComponent() en una URL completa, codificará los caracteres ://, /, ? y & — haciendo la URL completamente inutilizable. Solo codifica los valores individuales de los parámetros.

2. Olvidar codificar fragmentos hash. El carácter # en una URL inicia un identificador de fragmento. Si tus datos contienen un # y no lo codificas, todo lo que viene después desaparece desde la perspectiva del servidor. El servidor nunca ve los identificadores de fragmento — son solo del lado del cliente.

3. No manejar nombres de dominio internacionales (IDN). Los nombres de dominio con caracteres no ASCII como example.日本 necesitan un manejo especial llamado codificación Punycode. Esto es independiente de la codificación por porcentaje y se aplica solo a la porción del nombre de host de la URL.

4. Codificar espacios de forma inconsistente. Algunas partes de tu sistema podrían codificar espacios como + y otras como %20. Esto generalmente funciona bien para decodificar, pero puede causar problemas con la comparación de URLs y el caché. Elige una convención y mantenla.

Referencia rápida de codificación por porcentaje

CarácterCodificadoPor qué necesita codificación
Espacio%20 o +No permitido en URLs
&%26Separa parámetros de consulta
=%3DSepara clave de valor
?%3FInicia el query string
#%23Inicia identificador de fragmento
%%25El propio carácter de escape
/%2FSeparador de ruta
@%40Usado en la sección de información de usuario

Codificación URL en diferentes contextos

La codificación URL no es solo para URLs del navegador. La encontrarás en estas situaciones comunes:

  • Peticiones API: Los parámetros de consulta en llamadas a APIs REST necesitan codificación adecuada, especialmente si contienen entrada del usuario
  • URLs de redirección: Cuando pasas una URL de retorno como parámetro (como ?redirect=https://...), toda la URL de redirección necesita ser codificada como valor
  • Flujos OAuth: Las URLs de callback de OAuth y los parámetros de estado son notoriamente complicados porque involucran múltiples capas de codificación URL
  • Deep links: Los deep links móviles siguen las mismas reglas de codificación URL, pero algunas plataformas tienen requisitos adicionales

Depurando problemas de codificación URL

Cuando algo sale mal con la codificación URL, aquí está mi lista de verificación para depurar:

1. Verifica la doble codificación — Busca %25 en la URL, lo que significa que un % fue codificado dos veces

2. Revisa la petición cruda — Usa la pestaña Network de las DevTools de tu navegador para ver exactamente qué URL se envió, antes de que el navegador muestre la versión decodificada

3. Compara codificado vs. decodificado — Pega la URL problemática en un decodificador para ver qué contiene realmente

4. Verifica la decodificación del lado del servidor — Algunos frameworks decodifican automáticamente los parámetros URL, y hacerlo manualmente encima de eso causa problemas

La anatomía de una URL

Bien, demos un paso atrás. Antes de profundizar más en la codificación, necesitas entender realmente de qué está hecha una URL. Lo sé, lo sé — has estado usando URLs toda tu carrera. Pero apuesto a que no conoces todas las partes por sus nombres oficiales. La mayoría de los desarrolladores no, y ahí es donde empieza la confusión con la codificación.

Según RFC 3986, una URL tiene esta estructura:

plaintext

Déjame explicarte cada parte:

  • Scheme (https, ftp, mailto) — El protocolo. No necesita codificación, siempre son letras ASCII.
  • Authority — Esto incluye el opcional user:password@ (que básicamente nunca deberías usar en 2026), el host (nombre de dominio o IP) y un número de puerto opcional.
  • Path (/search/results) — La parte jerárquica. Las barras / separan segmentos. Dentro de cada segmento, necesitas codificar caracteres especiales, pero NO codificas las barras en sí.
  • Query (?q=hello&lang=en) — Pares clave-valor después del ?. El & separa pares, = separa claves de valores. Codificas las claves y valores, pero no los & y = estructurales.
  • Fragment (#section-2) — La parte después del #. Esta es interesante — nunca se envía al servidor. Es puramente del lado del cliente. Pero aún necesitas codificar caracteres especiales dentro de ella.

Esto es lo que confunde a la gente: diferentes partes de la URL tienen diferentes reglas de codificación. Una / está perfectamente bien en la ruta (¡es un separador!) pero necesita ser codificada como %2F si aparece dentro del valor de un parámetro de consulta. Un signo @ está bien en la sección de autoridad pero debería codificarse en la ruta. Por eso las funciones de codificación de talla única causan tantos bugs.

Piénsalo así: la URL es una oración con reglas gramaticales. Los caracteres especiales son signos de puntuación. No codificarías una coma que realmente se está usando como coma — solo codificas una coma que es parte de los datos y podría confundirse con la puntuación.

encodeURI vs. encodeURIComponent: El campo minado de JavaScript

Bien, este tema me vuelve absolutamente loco porque veo a los desarrolladores equivocarse TODO el tiempo. JavaScript te da dos funciones de codificación, y suenan casi idénticas, pero usar la incorrecta arruinará tu día.

Déjame explicarlo claramente:

encodeURI() está diseñada para codificar una URL completa. Codifica caracteres inseguros pero deja los estructurales en paz — cosas como :, /, ?, #, &, =, @. Porque si estás codificando una URL completa, obviamente no quieres romper la estructura de la URL.

encodeURIComponent() está diseñada para codificar un valor individual que va dentro de una URL. Codifica TODO excepto letras, dígitos y - _ . ~. Esto incluye :, /, ?, #, &, = — porque cuando estos aparecen en un valor, son datos, no estructura.

Aquí hay una comparación que lo deja cristalino:

CarácterencodeURI()encodeURIComponent()
:: (sin cambio)%3A
// (sin cambio)%2F
?? (sin cambio)%3F
## (sin cambio)%23
&& (sin cambio)%26
== (sin cambio)%3D
@@ (sin cambio)%40
Espacio%20%20
é%C3%A9%C3%A9

Ahora se pone preocupante. Mira lo que pasa cuando usas la función incorrecta:

javascript

Y el error opuesto es igual de malo:

javascript

La regla de oro: encodeURIComponent para valores, encodeURI para URLs completas. O mejor aún, simplemente usa la API URL y deja que el navegador se encargue. En serio, las clases URL y URLSearchParams existen por una razón. Consulta la documentación de MDN para encodeURIComponent y la documentación de MDN para encodeURI para todos los detalles.

Codificación URL en diferentes lenguajes

JavaScript no es el único lenguaje con funciones confusas de codificación URL. Cada lenguaje tiene sus propias peculiaridades, y te juro que algunos son incluso más confusos que el par de JavaScript.

Python — En realidad bastante razonable, una vez que encuentras el módulo correcto:

python

Java — Aquí es donde se pone raro. URLEncoder fue diseñado para codificación de formularios HTML, no para codificación URL general. Así que los espacios se convierten en + en lugar de %20:

java

C# — .NET en realidad te da las herramientas correctas, pero hay como cinco métodos diferentes y todos hacen cosas ligeramente distintas:

csharp

PHP — Oh PHP. Por supuesto que tienes dos funciones con nombres casi idénticos que hacen cosas ligeramente diferentes:

php

Go — Limpio y sensato, como Go suele ser:

go

La conclusión: cada lenguaje maneja el tema + vs. %20 de forma diferente, y cada lenguaje tiene al menos una función que te sorprenderá. Siempre revisa la documentación del lenguaje con el que estés trabajando. No asumas que funciona igual que en JavaScript.

Unicode en URLs: El Salvaje Oeste

Bien, aquí es donde se pone REALMENTE interesante. ¿Qué pasa cuando pones caracteres no ASCII en una URL? Como, ¿qué pasa si quieres una URL con japonés, árabe o — no es broma — emoji?

La respuesta involucra dos sistemas completamente diferentes, y mezclarlos es un error clásico.

Para las partes de ruta y consulta: Usas codificación por porcentaje. Toma los bytes UTF-8 del carácter y codifica cada uno. Así que café se convierte en caf%C3%A9. Tu navegador hace esto automáticamente y generalmente te muestra la versión bonita en la barra de direcciones, pero internamente envía la versión codificada por porcentaje.

Para nombres de dominio: La codificación por porcentaje NO se usa. En su lugar, existe este sistema llamado Punycode. Convierte nombres de dominio Unicode en strings compatibles con ASCII que empiezan con xn--.

Mira esto:

  • café.comxn--caf-dma.com
  • münchen.dexn--mnchen-3ya.de
  • 例え.jpxn--r8jz45g.jp

¿Por qué dos sistemas diferentes? Porque DNS (el sistema que convierte nombres de dominio en direcciones IP) fue construido en los años 80 y solo soporta ASCII. Así que tuvieron que inventar una forma de meter Unicode en strings ASCII — y Punycode es esa invención. Las partes de ruta y consulta de una URL, por otro lado, son manejadas por servidores web que pueden lidiar con bytes codificados por porcentaje.

De hecho existe toda una especificación para Unicode en URLs llamada IRI (Internationalized Resource Identifiers) definida en RFC 3987. Un IRI es básicamente una URL que permite caracteres Unicode directamente. Los navegadores convierten IRIs a URIs detrás del escenario.

Y sí, los dominios con emoji existen. 💩.la es un dominio real (o lo fue en algún momento). Se codifica con Punycode a xn--ls8h.la. No recomiendo usar dominios emoji para nada serio, pero es una prueba divertida de que el sistema funciona.

Una trampa con Unicode en URLs: diferentes representaciones Unicode del "mismo" carácter. Por ejemplo, é puede representarse como un solo codepoint (U+00E9) o como e + una marca de acento combinante (U+0065 + U+0301). Estos producen strings codificados por porcentaje diferentes. El Estándar URL de WHATWG recomienda normalización NFC, pero no todos los sistemas siguen esto de manera consistente.

Doble codificación: El bug que persigue tus sueños

Mencioné la doble codificación antes, pero merece su propia inmersión profunda porque este bug probablemente ha desperdiciado más horas colectivas de desarrolladores que cualquier otro problema relacionado con URLs. He estado ahí, lo he vivido — varias veces.

Aquí está el escenario básico:

plaintext

¿Qué pasó? Cuando codificas hello%20world una segunda vez, el carácter % se codifica a %25. Así que %20 se convierte en %2520. El servidor ve el string literal %20 en lugar de un espacio.

Esto suena obvio cuando lo escribo así, pero en bases de código reales es increíblemente astuto. Aquí están los escenarios donde la doble codificación te muerde:

Cadenas de proxy. Envías una petición al servidor A, que la reenvía al servidor B. Si ambos servidores codifican la URL, boom — doble codificación. API gateways como Kong, AWS API Gateway o proxies reversos de nginx son culpables comunes.

Cadenas de redirección. El usuario va a la página A, es redirigido a la página B con un parámetro ?returnUrl=..., y la página B redirige de nuevo con la URL de retorno como parámetro. Cada redirección podría re-codificar la URL. Después de tres redirecciones, tu URL está triple codificada y completamente destrozada.

"Ayudantes" de framework. Algunos frameworks web codifican automáticamente los parámetros URL. Si codificas manualmente antes de pasar al framework, obtienes doble codificación. He visto esto pasar con Spring Boot, middleware de Express.js y el reversado de URLs de Django.

¿Cómo detectas la doble codificación? Busca %25 en la URL. Eso es un signo de porcentaje que fue codificado, lo que generalmente significa que algo fue codificado dos veces. Si ves %2520, es un espacio doble codificado. Si ves %253D, es un signo = doble codificado.

Cómo arreglarlo:

javascript

La mejor defensa es establecer límites claros en tu código: codifica en los bordes (justo antes de enviar una petición HTTP, o justo antes de construir una URL para mostrar), y pasa strings crudos y sin codificar por todas partes internamente.

Límites de longitud de URL y qué hacer al respecto

Aquí hay algo que te sorprenderá: la especificación HTTP en sí NO define una longitud máxima de URL. RFC 3986 dice que las URLs deberían ser "de longitud ilimitada". Pero el mundo real no está de acuerdo.

Diferentes componentes en la cadena tienen sus propios límites, y el más corto gana:

ComponenteLongitud máxima de URL
Internet Explorer (DEP)2,083 caracteres
Chrome, Firefox, Safari~65,000+ caracteres
Apache (por defecto)8,190 caracteres
Nginx (por defecto)8,192 caracteres
IIS (por defecto)16,384 caracteres
AWS ALB8,192 caracteres
Cloudflare32,768 caracteres

Ese viejo límite de 2,083 caracteres de IE solía gobernar todo. Aunque IE está básicamente muerto ahora, algunos desarrolladores y herramientas todavía lo tratan como verdad absoluta. Pero en la práctica, la mayoría de los stacks modernos pueden manejar URLs mucho más largas.

Dicho esto, solo porque PUEDAS hacer una URL de 65,000 caracteres no significa que DEBAS. Aquí hay algunas razones reales para mantener las URLs cortas:

  • Logs del servidor. Muchos sistemas de logging truncan URLs largas, lo que hace que la depuración sea una pesadilla.
  • Copiar y pegar. Los usuarios copian y comparten URLs. Las URLs super largas se rompen en correos, mensajes de chat y documentos.
  • SEO. Los motores de búsqueda generalmente recomiendan mantener las URLs por debajo de 2,000 caracteres.
  • Caché. Algunos límites de clave de caché de CDN y proxy se basan en URLs. URLs más largas = más fallos de caché.

¿Entonces qué haces cuando tu URL se está haciendo muy larga? Me alegra que preguntes:

1. Usa POST en lugar de GET. Si estás enviando muchos datos, ponlos en el cuerpo de la petición. El cuerpo de la petición no tiene límite de tamaño práctico. Esta es la solución más común para formularios de búsqueda complejos con muchos filtros.

2. Usa acortadores de URL o IDs de referencia. Genera un token corto que se mapee al conjunto completo de parámetros almacenados en el servidor. Así que en lugar de /search?filter1=abc&filter2=def&filter3=... obtienes /search/saved/abc123.

3. Comprime tus parámetros. Algunas apps codifican en base64 un blob JSON comprimido y lo ponen en la URL. No es bonito, pero funciona. Verás esto en herramientas como las URLs de dashboards de Grafana.

Codificación de formularios: application/x-www-form-urlencoded

Hablemos del elefante en la habitación que hace la codificación URL aún más confusa: la codificación de formularios HTML. Cuando envías un formulario HTML con method="POST", el navegador codifica los datos del formulario usando un formato llamado application/x-www-form-urlencoded. Y este formato es CASI igual que la codificación por porcentaje estándar, pero con una diferencia clave que vuelve loco a todo el mundo.

Los espacios se convierten en + en lugar de %20.

Eso es todo. Esa es la diferencia principal. Pero vaya que causa confusión.

plaintext

¿Por qué existe esta diferencia? Razones históricas, por supuesto. La especificación de codificación de formularios HTML es anterior a la especificación de codificación URL, y usaba + para espacios porque... bueno, alguien pensó que se veía mejor en los '90. Y ahora estamos atrapados con eso para siempre.

Cuando envías un formulario HTML, el navegador envía un header Content-Type: application/x-www-form-urlencoded, y el servidor sabe interpretar + como espacios. Pero si estás construyendo URLs manualmente en JavaScript y usas + para espacios en la parte de la ruta, el servidor verá signos de más literales. Tiempos divertidos.

Aquí es donde importa en la práctica:

javascript

Y luego está multipart/form-data, que es una bestia completamente diferente. Cuando tu formulario incluye subida de archivos (), el navegador cambia a codificación multipart/form-data, que usa delimitadores para separar campos en lugar de signos &. No usa codificación URL en absoluto — cada parte tiene sus propios headers y body. Si alguna vez has intentado parsear manualmente una petición multipart, conoces el dolor.

El consejo práctico: usa URLSearchParams para query strings y datos de formulario. Usa FormData para subida de archivos. No intentes codificar estas cosas a mano a menos que realmente, realmente tengas que hacerlo.

Pruébalo tú mismo

¿Trabajando con URLs que se ven mal? Pégalas en nuestro Decodificador URL para ver los caracteres reales. ¿Necesitas codificar un valor antes de ponerlo en una URL? El Codificador URL lo maneja al instante. Y para descomponer URLs complejas en sus componentes, usa el Analizador de URL para ver cada parte claramente.