RunnerSoft

BLOG · Desarrollo Web

Codificar y decodificar URL: %20 o +, encodeURI y encodeURIComponent

Aprende qué es la codificación de URL, cuándo codificar un valor o una URL completa, la diferencia entre %20 y + y cómo evitar la doble codificación.

Actualizado: 2026-10-16

Cuando escribes un enlace con un espacio, un acento o un símbolo como el ampersand, el navegador no puede enviarlo tal cual: lo transforma en secuencias con porcentaje. Entender cuándo y cómo se hace evita enlaces rotos, parámetros que se pierden y, en el peor caso, fallos de seguridad. Esta guía resume cómo funciona y cómo usar nuestro codificador de URL.

Qué es la codificación porcentual

Una URL solo admite un conjunto limitado de caracteres. Los demás se escriben como un signo de porcentaje seguido de dos dígitos hexadecimales que representan un byte. Los caracteres no ASCII se convierten primero a UTF-8, y cada byte resultante se escribe así:

  • El espacio se convierte en %20.
  • La letra é (dos bytes en UTF-8) se convierte en %C3%A9.
  • Un emoji ocupa cuatro bytes: 😀 se convierte en %F0%9F%98%80.

Según el estándar de URLs (RFC 3986), los caracteres que nunca necesitan codificarse son letras, números y los símbolos guion, punto, guion bajo y tilde. El resto se divide en dos grupos: los reservados, que tienen función dentro de la URL (como la barra, el signo de interrogación, el ampersand, el igual o la almohadilla), y los demás, que deben codificarse siempre.

Codificar un valor o una URL completa

Este es el error más frecuente. Hay dos operaciones distintas:

  • Codificar un valor se usa para un dato que va dentro de la URL, como un parámetro. Debe escapar también los caracteres reservados, porque dentro de un valor no pueden tener función especial. En JavaScript es encodeURIComponent.
  • Codificar una URL completa se usa cuando ya tienes la dirección armada y solo quieres escapar espacios o acentos. Debe conservar los caracteres reservados, porque son su estructura. En JavaScript es encodeURI.

Con la misma entrada, https://ejemplo.com/a b?x=1&y=2, los resultados son muy distintos:

Como URL completa:  https://ejemplo.com/a%20b?x=1&y=2
Como valor:         https%3A%2F%2Fejemplo.com%2Fa%20b%3Fx%3D1%26y%3D2

El segundo resultado es correcto si esa dirección será el valor de un parámetro (por ejemplo, un enlace de retorno), pero inservible como enlace directo. Nuestra herramienta ofrece un botón para cada caso.

%20 o +: cuál es la diferencia

El espacio puede aparecer de dos maneras:

  • %20 es válido en cualquier parte de una URL.
  • El signo + solo representa un espacio en datos de formularios (formato application/x-www-form-urlencoded), es decir, en la parte de consulta. En una ruta, un + es un más literal.

Por eso un + puede significar cosas distintas según el contexto, y decodificarlo mal cambia el dato. Un valor como 1+1=2 se codifica como 1%2B1%3D2 precisamente para que el más no se confunda con un espacio.

El error de la doble codificación

Si codificas un texto que ya está codificado, el signo de porcentaje se escapa también. Un resultado con %2520 es la señal clásica: hola%20mundo se convierte en hola%2520mundo. Al decodificar una sola vez ya no obtienes el texto original, sino otra cadena codificada. Codifica siempre el dato original, una sola vez y en el último momento, justo antes de armar la URL.

Cómo hacerlo en código

JavaScript. Para valores usa encodeURIComponent; para armar parámetros, URLSearchParams, que gestiona la codificación por ti (y escribe el espacio como +, siguiendo el formato de formularios).

PHP. Hay dos pares de funciones que se parecen mucho y no son iguales:

rawurlencode('hola mundo');   // hola%20mundo   (estándar RFC 3986)
urlencode('hola mundo');      // hola+mundo     (formato de formularios)

// http_build_query usa + para los espacios por defecto.
// Para obtener %20, indica el tipo de codificación:
http_build_query(['q' => 'hola mundo'], '', '&', PHP_QUERY_RFC3986);

Al decodificar, urldecode convierte el + en espacio y rawurldecode no. Usa el par que corresponda al origen del dato.

Por qué importa para la seguridad

Concatenar texto de un usuario directamente en una URL abre la puerta a la inyección de parámetros. Si armas el enlace así y el nombre llega como ana&rol=admin, la dirección resultante contiene un parámetro rol que tú no pusiste:

https://miapp.com/perfil?nombre=ana&rol=admin

Codificar el valor convierte el ampersand y el igual en datos inertes (ana%26rol%3Dadmin). Es la misma idea que escapar texto antes de ponerlo en HTML o en una consulta SQL: el dato no debe poder cambiar la estructura que lo contiene.

Un caso práctico: si una contraseña con símbolos va dentro de una cadena de conexión con formato usuario:contraseña@servidor, caracteres como la arroba, los dos puntos, la barra, la almohadilla o el porcentaje deben codificarse o la conexión fallará. Si generas contraseñas con nuestra guía de contraseñas seguras, esto te conviene tenerlo presente.

Lo que comprobamos en nuestro codificador

Estas son las entradas que probamos y lo que devolvió:

  • hola mundo se convierte en hola%20mundo.
  • café ñandú se convierte en caf%C3%A9%20%C3%B1and%C3%BA.
  • a&b=c se convierte en a%26b%3Dc.
  • Un emoji se convierte en cuatro bytes: %F0%9F%98%80.
  • 1+1=2 como valor se convierte en 1%2B1%3D2; como URL completa se queda igual.
  • Los símbolos guion, guion bajo, punto, signo de exclamación, tilde, asterisco, apóstrofo y paréntesis no se codifican al codificar un valor.
  • Al decodificar, a+b se queda como a+b, salvo que actives la casilla que interpreta el más como espacio.
  • Decodificar un texto con un porcentaje suelto, como 100%, muestra un mensaje de error.
  • Codificar hola%20mundo otra vez devuelve hola%2520mundo.

Resumen rápido

  • Un dato dentro de una URL se codifica como valor; una dirección ya armada, como URL completa.
  • En formularios el espacio puede ser +; en el resto de la URL es %20.
  • Codifica una sola vez y nunca concatenes texto de usuario sin codificar.
  • En PHP, rawurlencode es el más cercano al estándar; urlencode sigue el formato de formularios.

Referencias