Por qué las URLs necesitan codificación
Una URL está compuesta por caracteres, y no todos son "seguros" para usarse directamente. Las URLs se transmiten a través de Internet por sistemas que pueden interpretar ciertos caracteres como portadores de un significado especial —por ejemplo, ? para cadenas de consulta, & para separar parámetros, o # para identificadores de fragmento. Otros caracteres pueden ser no ASCII (como letras chinas o árabes), y algunos pueden corromperse al pasar por infraestructuras HTTP antiguas.
La codificación de URL (denominada oficialmente percent-encoding) resuelve esto reemplazando los caracteres inseguros por % seguido de la representación hexadecimal de dos dígitos del valor de byte del carácter.
Un espacio (0x20) → %20
Un símbolo @ (0x40) → %40
Una barra diagonal (0x2F) → %2F
El estándar RFC
La codificación de URL está definida en RFC 3986 (Identificadores de Recursos Uniformes). Según este estándar:
Caracteres no reservados — se pueden usar en cualquier parte de una URL sin codificación:
- A–Z, a–z, 0–9
-,_,.,~
Caracteres reservados — tienen un significado especial en las URIs y deben codificarse con percent-encoding cuando se usan como datos:
: / ? # [ ] @ ! $ & ' ( ) * + , ; =
Todo lo demás —incluyendo espacios, caracteres no ASCII y caracteres como ", <, >, {, }— debe codificarse con percent-encoding.
Percent-encoding en la práctica
Codificar un espacio
El carácter espacio (U+0020) se codifica como %20. También es posible ver + en lugar de %20 en las cadenas de consulta — esto proviene del estándar de codificación de formularios HTML (application/x-www-form-urlencoded), donde los espacios se codifican como +. Los dos son distintos:
%20— percent-encoding según RFC 3986 (espacios en rutas y cabeceras)+— codificación de formularios HTML (espacios en cadenas de consulta)
Al decodificar, siempre identifica qué convención aplica para evitar errores.
Caracteres no ASCII
Los caracteres no ASCII se codifican primero en UTF-8 y luego cada byte se codifica con percent-encoding:
Carácter chino 中 (U+4E2D)
Bytes UTF-8: 0xE4 0xB8 0xAD
Percent-encoded: %E4%B8%AD
Así, la palabra en español España contiene caracteres que requieren codificación según el contexto en el que aparezcan.
Funciones de codificación en JavaScript
JavaScript proporciona varias funciones incorporadas para la codificación de URL:
encodeURI()
Codifica una URI completa — diseñada para codificar una URL completa preservando su estructura. No codifica los caracteres que forman parte de la sintaxis URI: ; , / ? : @ & = + $ #.
encodeURI("https://example.com/search?q=hola mundo&lang=español")
// "https://example.com/search?q=hola%20mundo&lang=espa%C3%B1ol"
encodeURIComponent()
Codifica un componente de URI — diseñada para codificar valores individuales como los valores de parámetros de consulta. Codifica todo excepto A–Z a–z 0–9 - _ . ! ~ * ' ( ).
encodeURIComponent("hola mundo & más")
// "hola%20mundo%20%26%20m%C3%A1s"
encodeURIComponent("https://example.com")
// "https%3A%2F%2Fexample.com"
Cuándo usar cada una
| Escenario | Función |
|---|---|
| Codificar una URL completa | encodeURI() |
| Codificar un valor de parámetro de consulta | encodeURIComponent() |
| Codificar un segmento de ruta | encodeURIComponent() |
| Codificar una URL para incrustarla en otra | encodeURIComponent() |
Las funciones de decodificación complementarias
decodeURI(encodedURI)
decodeURIComponent(encodedComponent)
Nunca uses las funciones obsoletas escape() y unescape() — manejan los caracteres no ASCII de manera diferente y producen resultados incorrectos.
Errores comunes y trampas
Doble codificación
Un error frecuente es codificar una cadena que ya está codificada:
encodeURIComponent(encodeURIComponent("hola mundo"))
// "hola%2520mundo"
// %25 es la codificación de %, por lo que %20 se convirtió en %2520
Siempre verifica si el valor ya está codificado antes de volver a codificarlo.
La trampa de + vs %20
Si decodificas con decodeURIComponent una cadena de consulta que usa + para los espacios, el + no se decodificará como espacio — debes reemplazar primero + por %20, o usar la API URLSearchParams:
new URLSearchParams("q=hola+mundo").get("q")
// "hola mundo" ✓
decodeURIComponent("hola+mundo")
// "hola+mundo" ✗ — todavía tiene un signo más literal
Identificadores de fragmento
El carácter # en las URLs marca el inicio de un identificador de fragmento (para anclas dentro de la página). Si tienes un # en datos, debe codificarse como %23; de lo contrario, el navegador tratará todo lo que sigue como un fragmento.
Nombres de dominio internacionalizados (IDN)
Los nombres de dominio con caracteres no ASCII (como bücher.de) usan codificación Punycode, no percent-encoding. Los navegadores convierten los IDN a Punycode internamente: bücher.de → xn--bcher-kva.de.
Referencia de estructura de URL
Una URL tiene los siguientes componentes (según RFC 3986):
scheme://userinfo@host:port/path?query#fragment
| Componente | Ejemplo | Reglas de codificación |
|---|---|---|
| Scheme | https | Letras, dígitos, +, -, . |
| Host | example.com | Etiquetas de dominio + puntos |
| Port | 8080 | Solo dígitos |
| Path | /search/results | Codificado con %XX excepto no reservados + :@!$&'()*+,;= |
| Query | q=hola+mundo | + para espacios en datos de formulario, %20 en general |
| Fragment | #section-2 | No se envía al servidor; solo navegador |
Consideraciones del lado del servidor
Normalización de URLs
Los servidores deben normalizar las URLs antes de procesarlas — por ejemplo, tratar %41 (que decodifica a A) igual que A. Sin embargo, algunos caracteres tienen diferentes significados codificados vs no codificados: / vs %2F en rutas — muchos servidores web los tratan de manera diferente por razones de seguridad (protección contra path traversal).
Inyección SQL a través de parámetros de URL
Siempre sanitiza y valida los parámetros de URL antes de usarlos en consultas de base de datos, incluso después de decodificarlos. La codificación de URL no es un límite de seguridad.
Herramientas y APIs
La API URL del navegador
Los navegadores modernos y Node.js proporcionan la API URL para trabajar con URLs de manera estructurada:
const url = new URL("https://example.com/search?q=hola mundo&page=1");
console.log(url.searchParams.get("q")); // "hola mundo" (decodificado automáticamente)
url.searchParams.set("q", "nuevo valor & especial");
console.log(url.href);
// https://example.com/search?q=nuevo+valor+%26+especial&page=1
La API URL gestiona la codificación/decodificación de forma transparente, lo cual generalmente es el enfoque preferido frente a las llamadas manuales a encodeURIComponent.
Resumen
La codificación de URL es un concepto fundamental que todo desarrollador web encuentra a diario, a menudo sin notarlo. Los puntos clave a recordar:
- El percent-encoding (
%XX) es el mecanismo estándar para codificar caracteres inseguros en URIs. - Usa
encodeURIComponent()para valores individuales yencodeURI()para URLs completas. - Ten en cuenta la distinción entre
+y%20en las cadenas de consulta. - Evita la doble codificación — comprueba si una cadena ya está codificada antes de codificarla.
- Prefiere las APIs modernas
URLyURLSearchParamspara trabajar con URLs de forma programática.