Ir al contenido
Allin

Construir una URL con parámetros que sobreviva a un copiar y pegar

Publicado el 11/8/2026 · 12 min de lectura · Herramientas para desarrolladores

Daniel Okonkwo

Daniel OkonkwoDesarrollador front-end y redactor de Tecnología en Allin

Rendimiento web · Formatos de archivo

Verificado con 4 fuentes

Ver perfil
En resumen

Una cadena de consulta se rompe cuando un carácter que significa algo para la URL —un espacio, un ampersand, un signo igual, una almohadilla— se deja tal cual dentro de un valor. La codificación por ciento lo arregla, pero hay tres codificaciones y discrepan, y la discrepancia se ve en el espacio. encodeURIComponent escribe un espacio como %20 y deja intactos ! ' ( ) * ~. El serializador application/x-www-form-urlencoded, el que usan URLSearchParams y todos los formularios HTML, escribe un espacio como + y codifica ! ' ( ) ~ dejando intacto el *. El RFC 3986 estricto codifica todo lo que queda fuera de A-Z a-z 0-9 - . _ ~, así que también escapa el * y conserva el ~. Este generador ofrece las tres, y su modo formulario se comparó con el URLSearchParams de Node sobre diecisiete valores, incluidos un emoji, un salto de línea y una cadena con acentos: idéntico byte a byte cada vez. Sí codifica dos veces: escribe %20 como valor y obtienes %2520. Es correcto —estás escribiendo un valor en crudo, no uno ya codificado— y el analizador de la propia herramienta lo devuelve al literal %20. El fallo de verdad está en otro sitio. Dale una URL base con un fragmento, https://example.com/page#section, y la cadena se añade después del fragmento: el analizador de URL del navegador informa entonces de una parte de consulta vacía y mete todos los parámetros dentro del hash, donde ningún servidor los verá jamás. Su analizador también tira el fragmento, y una secuencia heredada como %E9 falla al decodificarse, se conserva como texto literal y vuelve como %25E9 en la siguiente construcción.

Tres codificaciones, una diferencia visible: %20 o +. El modo formulario del generador reproduce URLSearchParams byte a byte en diecisiete valores, pero dale una URL base con un fragmento y todos los parámetros acaban dentro del hash, donde ningún servidor los ve.

Dos normas, y los navegadores aplican la más reciente

El RFC 3986 es el documento más antiguo y el que todo el mundo cita. Reparte los caracteres entre no reservados —A-Z, a-z, 0-9 y los cuatro signos - . _ ~— y todo lo demás, reservado o pendiente de codificar por ciento. Es un modelo limpio y no es el que ejecuta tu navegador. Los navegadores aplican el WHATWG URL Standard, un documento vivo que especifica el análisis y la serialización mediante varios conjuntos de codificación con nombre, uno por parte de la URL. Ambos coinciden en los casos comunes y divergen en los bordes, y en los bordes es donde una URL deja de funcionar.

El estándar URL es explícito sobre esa relación. Indica que usar su conjunto de codificación «component» con UTF-8 da resultados idénticos a encodeURIComponent de JavaScript. Y define el conjunto application/x-www-form-urlencoded como el conjunto component más ! ' ( ) ~, y luego dice lo mismo al revés, en la frase que conviene memorizar: ese conjunto contiene todos los puntos de código salvo los alfanuméricos ASCII y * - . _ . Cuatro caracteres. Esa es la lista segura completa de un envío de formulario, y explica de un vistazo por qué los dos modos discrepan exactamente en ! ' ( ) ~ mientras ambos dejan intacto el asterisco.

El tercer modo del generador, RFC 3986 estricto, es el que hay que usar cuando un servidor firma la URL. Toma la salida de encodeURIComponent y escapa además ! ' ( ) * , dejando intacto el ~, porque la tilde es no reservada en el RFC 3986 y escaparla cambiaría la firma. Las pasarelas de pago, las firmas OAuth 1.0 y algunas API empresariales antiguas calculan un hash sobre la cadena codificada, así que un codificador que deja un apóstrofo tal cual produce un hash distinto del suyo y la petición se rechaza sin ninguna explicación aprovechable.

Sí codifica dos veces, y es la respuesta correcta

La doble codificación es la queja clásica contra los generadores de URL, así que se probó directamente. Escribe %20 en un campo de valor y la salida es %2520. Escribe caf%C3%A9 y obtienes caf%25C3%25A9. Escribe un simple signo de porcentaje y obtienes %25. No es un fallo: es la definición del campo. La casilla de valor contiene el valor que escribió tu usuario, y si ese valor es realmente la secuencia c a f % 2 0, entonces %2520 es la única codificación que la entregará.

La forma de comprobar si un generador acierta en esto no es mirar una salida, sino hacer una ida y vuelta. Construye una URL, pégala de vuelta en el campo de análisis de la herramienta y vuelve a construir. Seis valores pasaron por ese ciclo —una frase con acentos y un ampersand, un signo más, un %20 literal, una almohadilla dentro de un valor, un valor vacío y un objeto JSON— y los seis volvieron idénticos byte a byte. El %2520 pegado se decodificó al literal %20, que se recodificó a %2520. Un generador que quitara una capa para quedar limpio fallaría justo aquí, en silencio, en el único valor que importa.

El fallo: un fragmento en la URL base se traga todos los parámetros

El generador une su cadena a la base buscando un signo de interrogación: si la base ya tiene uno, añade con un ampersand; si no, añade con un signo de interrogación. Las dos ramas añaden al final. Una URL no funciona así. El orden de las partes es fijo —esquema, autoridad, ruta, consulta, fragmento— y el fragmento va el último, así que todo lo que se escriba después le pertenece.

Pon la base en https://example.com/page#section, añade q y page, y la herramienta imprime https://example.com/page#section?q=caf%C3%A9%20%26%20croissant&page=2. Parece correcto. Entrega esa cadena al analizador de URL del navegador e informa de una ruta /page, una parte de consulta vacía y un hash que contiene #section?q=caf%C3%A9%20%26%20croissant&page=2: todos los parámetros dentro del fragmento. Un fragmento nunca se envía al servidor. La página cargará, no aparecerá ningún error en ninguna parte y los parámetros sencillamente no existirán para nada del lado del servidor. La variante con una consulta ya presente, https://example.com/page?a=1#frag, cuenta lo mismo: la parte de consulta vuelve como ?a=1 y los nuevos parámetros están dentro del hash.

El análisis tiene el problema simétrico: parte la entrada en la primera almohadilla y tira todo lo que va después. Pega https://example.com/p?a=1#frag y la base vuelve como https://example.com/p, sin fragmento. Así que no puedes usar la herramienta en absoluto con una URL que tenga fragmento: lo pierde a la entrada y coloca mal la consulta a la salida. Mientras no se corrija, el apaño es quitar el fragmento tú mismo, construir la cadena y volver a montar a mano: la base, luego la consulta, luego la almohadilla, en ese orden.

Tres detalles menores que conviene saber antes de fiarse

Primero, un escape por ciento que no sabe decodificar se conserva como texto literal y luego se vuelve a codificar a la salida. Pega una URL con a=%E9 —un escape Latin-1 de un solo byte, como los que todavía emiten muchísimos sistemas anteriores a 2010— y el decodificador lanza un error, la herramienta lo captura y guarda los tres caracteres % E 9 como valor. Vuelve a construir y se convierte en a=%25E9, una URL distinta de la que pegaste. Nada te avisa. Lo prudente es revisar cualquier parámetro que vuelva conteniendo un signo de porcentaje.

Segundo, el generador agrupa los parámetros por clave en vez de conservar el orden de tus filas. Las filas a=1, b=2, a=3 salen como a=1&a=3&b=2: las dos filas a se juntan y b baja. Para un servidor web normal es inofensivo, ya que casi nada se fija en el orden de los parámetros. Para una petición firmada no lo es, porque la firma se calcula sobre la cadena exacta. Compara la salida con el orden que escribiste siempre que el receptor haga un hash de la consulta.

Tercero, la opción de ordenar claves ordena con la comparación sensible a la configuración regional del navegador, no por punto de código. Con las claves b, a, B y _x produce _x, a, b, B. Un orden por punto de código —el que especifica cualquier esquema de firma existente— produce B, _x, a, b. Los dos difieren en cuanto tus claves mezclan mayúsculas y minúsculas o empiezan por un guion bajo, que es justo lo que suelen hacer los nombres de parámetros de una API firmada. Usa la opción para hacer legible una URL larga; no la uses para canonizarla.

Dos cosas que hace bien y que es fácil equivocar. Sus cuatro sintaxis de valores repetidos codifican todas los corchetes: a[]=1 se escribe a%5B%5D=1 y a[0]=1 se escribe a%5B0%5D=1, lo cual es correcto según el RFC 3986, donde los corchetes están reservados para literales de host IPv6, y lo que PHP, Rails y Express decodifican sin problema. Y en modo coma, la coma entre valores también se codifica: color=red,blue se escribe color=red%2Cblue, legal y seguro con cualquier servidor que decodifique antes de dividir.

El mismo valor a través de las tres codificaciones del generador, tal como las produjo
Valor escritoencodeURIComponentx-www-form-urlencodedRFC 3986 estricto
two wordstwo%20wordstwo+wordstwo%20words
café & croissantcaf%C3%A9%20%26%20croissantcaf%C3%A9+%26+croissantcaf%C3%A9%20%26%20croissant
C'est (chouette) !C'est%20(chouette)%20!C%27est+%28chouette%29+%21C%27est%20%28chouette%29%20%21
~tilde*star~tilde*star%7Etilde*star~tilde%2Astar
a=b&c#da%3Db%26c%23da%3Db%26c%23da%3Db%26c%23d
%20 escrito literalmente%2520%2520%2520
Generador de cadenas de consulta URLConstruye una cadena de consulta URL a partir de pares clave/valor, con codificación correcta, sintaxis de array y preajuste UTM — o analiza una URL existente.Probar la herramienta

Preguntas frecuentes

¿Qué codificación elijo si no sé qué espera el servidor?
Elige encodeURIComponent, el modo por defecto. Un espacio pasa a %20, que cualquier servidor decodifica bien, mientras que el + solo se interpreta como espacio en código que sabe que está leyendo datos de formulario. Esa asimetría es toda la razón para preferir %20 en una URL que vas a pegar en un correo, un mensaje de chat o una hoja de cálculo: sobrevive a que la lea algo que no sabe que viene de un formulario. Cambia a x-www-form-urlencoded solo cuando reproduzcas lo que enviaría un formulario del navegador, por ejemplo al depurar por qué un envío difiere de tu URL construida a mano. Cambia al RFC 3986 estricto cuando un servidor firme o haga un hash de la cadena de consulta, porque los escapes añadidos de ! ' ( ) * son los que producen casi todas las bibliotecas de firma.
¿Por qué desaparecieron mis parámetros cuando el enlace terminaba en #section?
Porque se escribieron después del fragmento, y todo lo que sigue a una almohadilla es el fragmento. Este generador añade la cadena al final de lo que le diste como base, así que una base https://example.com/page#section produce https://example.com/page#section?q=x, y el navegador lee toda la cola como un único fragmento. Un fragmento se resuelve enteramente en el cliente; no forma parte de la línea de petición y ningún servidor lo ve. Arréglalo a mano: toma la base sin su fragmento, añade la cadena y vuelve a poner el fragmento al final del todo, lo que da https://example.com/page?q=x#section. Si pegas esa URL corregida de vuelta en la herramienta, analizará bien la consulta pero perderá otra vez el fragmento, así que guarda el fragmento en otro sitio mientras trabajas.
¿Cómo envío una lista de valores para el mismo parámetro?
No hay norma, y por eso la herramienta ofrece cuatro sintaxis. Repetir la clave, color=red&color=blue, es lo que produce un formulario HTML cuando varias casillas comparten nombre, y lo que devuelve URLSearchParams.getAll; es el valor por defecto más seguro. Los corchetes, color[]=red&color[]=blue, son una convención de PHP que también leen Rails y varios frameworks de PHP. Los corchetes indexados, color[0]=red, conservan la posición y se usan donde el servidor reconstruye un array ordenado. Un valor unido por comas, color=red,blue, es un único parámetro con un único valor que el servidor divide él mismo. Elige la que documente tu servidor; si no documenta ninguna, repite la clave. Ten en cuenta que la herramienta codifica los corchetes y la coma, lo cual es legal y lo que todos esos frameworks decodifican antes de analizar.
¿Es prudente poner una dirección de correo o un número de pedido en una cadena de consulta?
Técnicamente funcionará, y aun así conviene evitarlo. Una cadena de consulta forma parte de la URL, y las URL se escriben en el historial del navegador, en los registros de acceso del servidor, en los de proxis y CDN, y en la cabecera Referer enviada a cualquier script de terceros que cargue la página. Cualquier dato personal que pongas ahí se copia a todos esos sitios por sistemas a los que nadie dijo que era personal, y se queda durante el periodo de retención de cada uno. Pon identificadores en la cadena sin problema —un id de producto, un número de página, un nombre de campaña— y pon todo lo que identifique a una persona en el cuerpo de una petición POST, o detrás de un token opaco corto que resuelva tu propio servidor. Lo mismo vale para cualquier cosa que conceda acceso: un token en una URL es un token en un archivo de registro.
¿Cuánto puede medir una URL antes de que algo la trunque?
Ninguna especificación fija un límite; cada implementación fija el suyo, y el que muerde primero no suele ser el navegador. El RFC 3986 se niega explícitamente a imponer un máximo y recomienda en cambio que todo lo que maneje URL soporte longitudes mayores de las que espera. En la práctica, los navegadores aceptan decenas de miles de caracteres, mientras que servidores web y proxis suelen rechazar una línea de petición por encima de unos 8 kilobytes y responden con un estado 414. Las herramientas de analítica y de resultados de búsqueda truncan mucho antes. El consejo práctico no depende de ninguna cifra exacta: si tu cadena de consulta llega a los miles de caracteres, los datos deben ir en un cuerpo POST o detrás de un identificador corto, no en un enlace. Las URL largas también se rompen al pegarse en clientes de correo y aplicaciones de mensajería, que las cortan en una columna y convierten un enlace en dos.

Artículos que podrían interesarte

Todas las guías
Explicación¿Qué es un código QR?Un código QR es un código de barras 2D que una cámara lee para abrir un enlace o texto. Aquí tienes qué es, por qué guarda tanto, su anatomía y una nota de seguridad.Explicación¿Qué es una expresión cron?Una expresión cron programa una tarea para ejecutarse automáticamente a horas fijadas. Aquí tienes para qué sirve, sus cinco campos, cómo leerla y los fallos comunes.GuíaCodificación de URL explicada: el porcentaje y dónde muerdeLa codificación por porcentaje se decide componente a componente, y de ahí viene toda la confusión. Una barra es legal en una ruta y debe escaparse en un valor de consulta; un espacio es %20 en una ruta y puede ser + en un cuerpo de formulario. Aquí están los conjuntos exactos de la RFC 3986, las tres funciones de JavaScript que discrepan y las trampas.ExplicaciónExtraer todas las direcciones de correo o URL de un bloque de textoUna URL al final de una frase se queda con el punto; una dirección de correo al final de esa misma frase, no. Un nombre acentuado dentro de una dirección vuelve truncado. Cada caso se pasó por las herramientas y aquí está la salida exacta.ExplicaciónQué hay dentro de un JWT y qué no protegeUn JWT está firmado, no cifrado. Cualquiera que tenga el token puede decodificar la carga y leer todas sus reclamaciones. Aquí tienes un token real, decodificado sin ninguna clave, más los tres ataques que la firma debe frenar y el único problema que no puede resolver.ComparativaJSON vs XML: ¿cuál es la diferencia?JSON y XML almacenan ambos datos estructurados como texto, pero con compromisos distintos. Aquí tienes cómo se ve cada uno, dónde gana cada uno y cómo elegir.

Herramientas relacionadas

Estas cifras salen de ejecutar estas herramientas sobre archivos reales y comprimir el resultado, no de la promesa de un fabricante. El peso depende por completo del archivo: una hoja de estilos escrita con comentarios largos no se comprime igual que una sin ellos, y tus números no serán los nuestros. Los minificadores tampoco son equivalentes —dos de este sitio discrepan ante la misma entrada—, así que trata cualquier salida minificada como código nuevo que hay que revisar antes de publicarlo. Guarda el original legible en el control de versiones, minifica en la compilación y comprueba la página en un navegador antes de publicar.

Fuentes

¿Has detectado un error en este artículo?