Inspector de codificación porcentual

La codificación porcentual no es una sola regla sino varias, y no se ponen de acuerdo en una docena de caracteres. Esta página pasa el mismo texto por encodeURIComponent, encodeURI y la serialización application/x-www-form-urlencoded uno al lado de otro, marca los caracteres en los que no coinciden, imprime una fila por carácter con sus bytes UTF-8 y su clase RFC 3986, y dice cuántas veces se ha codificado una cadena. El lado de la decodificación lee una cadena con una regla estricta o permisiva e indica qué escape está roto y dónde, en lugar de devolver en silencio un resultado erróneo.
Todo el procesamiento se realiza localmente en su navegador — sus datos nunca se suben a ningún servidor.

¿No sabe qué es la codificación porcentual? La codificación porcentual explicada en lenguaje sencillo — qué es, por qué un espacio se convierte en %20 o en +, y qué significa que una URL muestre %25.
Qué hace esto:
Cómo leer los escapes:
encodeURIComponent
encodeURI
formulario (application/x-www-form-urlencoded)
Ctrl+Intro en la entrada ejecuta el modo activo.
Elija un modo y haga clic en su botón de acción. Codificar e inspeccionar muestra las tres codificaciones de su texto más una fila por carácter; Decodificar lee los escapes de vuelta y cuenta las capas. El botón Autocomprobación vuelve a ejecutar cada ejemplo documentado, cada carácter ASCII imprimible y las cadenas de capas registradas en el archivo de datos de esta página, e informa del recuento aquí.
Dónde no coinciden los codificadores:solo los caracteres de abajo los tratan de forma distinta los tres métodos. Todo lo demás pasa por los tres sin cambios, o los tres lo escapan de forma idéntica.
Cada carácter, una fila cada uno:los bytes UTF-8 en que se convierte un carácter, la clase que le asigna la RFC 3986 y el escape que escribe cada contexto. Las cuatro columnas de contexto son los conjuntos de codificación porcentual de WHATWG URL, que es lo que usa un navegador al construir una ruta, una consulta o un fragmento; una fila sombreada es un carácter que los tres codificadores tratan de forma distinta.
El conjunto exacto que escapa esta página para cada parte de una URL:impreso desde el propio codificador, así que esta tabla y el código que rellena las columnas de arriba no pueden desincronizarse. Todos los conjuntos también escapan los caracteres de control C0 (U+0000 a U+001F) y todos los puntos de código por encima de U+007E, por eso el texto no ASCII siempre se escapa en todos los contextos.
Estos conjuntos derivan de los conjuntos de codificación porcentual de WHATWG y difieren de ellos en dos puntos deliberados, ambos para que el ensamblado a mano sea seguro: un hash se escapa dentro de una consulta, porque un hash sin escapar empezaría el fragmento; y el conjunto de componentes se fija exactamente a los caracteres que escapa encodeURIComponent, apóstrofo incluido, mientras que el conjunto de formulario se fija a lo que escapa URLSearchParams. Las dos columnas de la tabla de arriba son, por tanto, el comportamiento propio de la plataforma y no una reimplementación. Esa lista también explica un resultado que sorprende a mucha gente: un signo de porcentaje lo escapan encodeURIComponent y encodeURI, pero no está en ninguno de los conjuntos de contexto de WHATWG, así que las columnas de ruta, consulta y fragmento de la tabla por carácter lo dejan tal cual. Un signo de porcentaje sin escapar en una URL que ensambló a mano sigue siendo un riesgo, porque el estándar espera que la entrada se haya validado antes: %41 dentro de una consulta es una sola A para muchos frameworks de servidor, y la lectura estricta de esta página trata un % suelto como un escape roto. Escribirlo usted mismo como %25 es el hábito más seguro, y la tabla por carácter muestra las dos grafías una al lado de la otra.
Cuántas veces se ha codificado esta cadena:cada ronda de decodificación es una capa. Un valor que se ha codificado dos veces empieza por%25donde una sola codificación dejaría%20, y un valor que se ha codificado tres veces empieza por%2525.
Los caracteres que una URL puede llevar tal cual:la RFC 3986 divide el rango ASCII en tres grupos, y las reglas de escape solo tienen sentido frente a esa división.
Los caracteres reservados no están prohibidos, están ocupados: significan algo para el analizador de URL. La regla que se deduce de la lista es breve — si un carácter es reservado y lo quiere como dato, escápelo; si es no reservado, nunca necesita escaparlo.
Los tres métodos, y lo que deja sin tocar cada uno:
Las listas son los conjuntos exactos que cada método deja sin escapar en el rango ASCII; la Autocomprobación verifica cada carácter ASCII imprimible contra ellas, así que la tabla no puede separarse de los codificadores que describe.
Tamaño máximo de entrada que acepta esta página, y por qué:la codificación porcentual es una sola pasada sobre el texto, así que, a diferencia de los conversores de base de este sitio, el coste crece en línea recta y no al cuadrado: no hay una longitud a partir de la cual la aritmética en sí sea el problema. Los límites de abajo existen porque la tabla por carácter se dibuja en el documento, y una tabla con un millón de filas es lo que de verdad detiene un navegador.
¿Qué es la codificación porcentual?

La codificación porcentual — también llamada codificación de URL, y en documentos antiguos escapado — es la regla que permite que una URL lleve caracteres que no tiene permiso para contener. Un escape porcentual son tres caracteres ASCII: un signo de porcentaje y dos dígitos hexadecimales, que representan un byte. %20 es el byte 0x20, que es un espacio. %2F es el byte 0x2F, que es una barra. No interviene nada más: el escape nombra un byte, no un carácter.

Como nombra bytes, primero hay que convertir el texto en bytes, y la codificación de bytes es UTF-8. De ahí vienen los escapes largos: un carácter chino son tres bytes UTF-8 y, por tanto, tres escapes, y un emoji son cuatro bytes y doce caracteres ASCII.

La versión de 30 segundos: un espacio es %20 como valor de URL pero + en datos de formulario; # es %23; un signo de porcentaje literal es %25. Los tres codificadores de esta página coinciden en las letras, los dígitos y -_., y no coinciden en una docena de signos de puntuación, la tilde entre ellos — por eso encodeURIComponent y encodeURI producen cadenas distintas para el mismo texto, y por eso el incorrecto de los dos puede partir un valor en dos parámetros de consulta.
Por qué una URL necesita esto

Un URI se define como una secuencia de caracteres ASCII (RFC 3986, sección 2.1), y dentro de ese rango ASCII algunos caracteres son reservados: son los signos de puntuación que dan estructura a la URL. Dos puntos y dos barras separan el esquema, una arroba separa la información de usuario del host, una interrogación empieza la consulta, una almohadilla empieza el fragmento, un ampersand separa los parámetros de consulta, y un signo de porcentaje introduce un escape.

Eso crea un problema y una laguna. El problema: un valor que contiene en sí uno de esos caracteres — un cuadro de búsqueda con «a&b», un nombre de archivo con una barra, una contraseña con dos puntos — cambiaría la estructura de la URL en la que viaja. La laguna: el propio signo de porcentaje, así que el codificador puede simplemente ampliar su propio alfabeto. % se escribe como %25, y los dos dígitos hexadecimales que siguen son caracteres no reservados normales.

Ejemplos resueltos

Estas son las salidas exactas de los tres codificadores que ejecuta esta página, con entradas elegidas porque se comportan de forma distinta entre sí. La página las recalcula delante de usted, y su Autocomprobación vuelve a verificar cada fila contra las implementaciones propias de la plataforma.

Los tres métodos, y cuándo es el correcto cada uno

La versión corta que evita la mayoría de los errores: todo lo que vaya a un único valor de parámetro pasa por encodeURIComponent (o por un serializador de formularios, que hace el mismo trabajo con un conjunto seguro distinto), y una URL completa ya ensamblada pasa por encodeURI si necesita escaparse en absoluto. Elegir el incorrecto de esos dos es el error de codificación porcentual más habitual en código web.

Los caracteres que puede llevar una URL, completos
Dos signos más, dos significados

Un espacio es el único carácter cuya codificación depende de adónde va el texto, y el signo más es la razón.

La trampa está en medio de esa tabla. En datos de formulario un signo más significa un espacio, así que un valor que contiene de verdad un signo más — un número de teléfono escrito como +44 20 7946 0958, una expresión aritmética, una dirección de correo con una etiqueta con más — tiene que viajar como %2B. Si viaja como signo más literal, el receptor lo lee como espacio, y +44 llega como « 44».

Codificado dos veces, y cómo reconocerlo

Una doble codificación ocurre cuando una cadena ya está escapada y después se vuelve a escapar. El signo de porcentaje del primer escape es un carácter más, así que se convierte en %25, y la capa de debajo sobrevive como texto visible.

Reconocerlo es cuestión de contar: decodifique la cadena una vez y mire el resultado. Si todavía contiene escapes que parecen deliberados — un %XX válido o un signo más de formulario donde se espera un espacio — hay otra capa. Si contiene %25 seguido de dos dígitos hexadecimales, la capa siguiente es seguramente un escape.

Dos notas prácticas. Primero, decodificar dos veces no es inofensivo: es una forma conocida de conseguir que un filtro de seguridad y el código que hay detrás vean cadenas distintas, así que un filtro que se ejecuta antes de una segunda decodificación filtra el texto equivocado. Segundo, el recuento de capas de aquí es una propiedad de la cadena, no una promesa sobre la intención: un valor legítimo puede tener una sola capa de profundidad, y uno roto puede tener dos.

Los errores que esta página está diseñada para detectar
  • Un valor codificado con encodeURI. Los separadores sobreviven, así que un valor que contiene & o = se parte en varios parámetros al otro lado. Compare las dos columnas de arriba de esta página con la entrada a&b=c: la columna de componente escapa los dos caracteres, la columna de encodeURI los mantiene.
  • Un signo más literal enviado como datos de formulario. Llega como espacio. Use %2B.
  • Un valor escapado dos veces «para estar seguro». No es más seguro. El receptor decodifica una vez y obtiene una cadena que todavía contiene escapes porcentuales, que es el mismo fallo que un juego de caracteres incorrecto, una capa más abajo.
  • Decodificar lo que nunca se codificó. Un signo de porcentaje literal en un texto — 100% seguro — no es un escape. En una lectura estricta es uno roto, en la posición que informa esta página; en una lectura permisiva sobrevive, por eso permisiva es el valor predeterminado aquí y no al revés.
  • Suponer que el escape debe ir en mayúsculas. La decodificación trata %2f y %2F como el mismo byte, y ambos son válidos. Las mayúsculas son solo la grafía canónica que recomienda la RFC 3986, y la que producirán otras herramientas.
  • Suponer que la codificación porcentual hace seguro el texto. Lo hace inequívoco dentro de una URL. No detiene la inyección, no es cifrado y no es un sanitizador: el escape tiene que ser el último paso antes del ensamblado, para el contexto en el que va a entrar el texto.
Respuestas rápidas

«¿Es un signo más un espacio en una URL?»

Solo en datos de formulario, y solo en la parte de consulta de un envío de formulario. En una ruta, en un fragmento y en la consulta de un enlace normal, un signo más es un signo más literal. Por eso esta página tiene un interruptor para ello en lugar de adivinar.

«¿Por qué mi enlace muestra %25?»

Porque algo codificó un signo de porcentaje. O bien un signo de porcentaje literal pasó por un codificador — 100% seguro se convierte en 100%25%20seguro — o bien una cadena que ya contenía un escape se codificó por segunda vez. Decodifique la cadena una vez y mire lo que sale: si el resultado todavía contiene %XX, hay otra capa.

«¿Importa que una barra dentro de un valor de consulta sea %2F o /?»

Para el analizador de URL, no: ambas llegan al servidor como una barra, y el conjunto de consulta de WHATWG deja la barra tal cual. Para la interoperabilidad, a veces sí: muchos frameworks de servidor ejecutan su propia decodificación sobre una cadena de consulta sin procesar, y algunos no se ponen de acuerdo sobre caracteres que nunca se escaparon. Cuando un valor se ensambla a mano en lugar de con un serializador, escapar explícitamente los caracteres reservados es el hábito más seguro.

«¿Por qué la columna de formulario escapa una tilde que las otras dos dejan tal cual?»

Porque el conjunto seguro del codificador de formularios es más estrecho: solo letras, dígitos y -_.*. El codificador de formularios de WHATWG escapa ~ ! ' ( ) aunque la RFC 3986 incluye ~ entre los no reservados. Ambas grafías se decodifican al mismo valor; la diferencia solo importa cuando se comparan cadenas byte a byte.

«¿Pueden aparecer los mismos caracteres sin escapar en la barra de direcciones del navegador?»

Sí, y eso es la barra de direcciones, no la URL. Los navegadores muestran una forma legible de la URL y la codifican al enviarla, así que 中文 en un enlace se convierte en %E4%B8%AD%E6%96%87 en la red. Si copia la URL desde la barra de direcciones puede obtener cualquiera de las dos formas según el navegador.

«Todos los escapes de aquí parecen válidos, pero el carácter que sale no es el que esperaba. ¿Por qué?»

Hay dos fallos distintos detrás de «se decodificó mal», y la página los informa de forma diferente. El primero es un escape roto: un signo de porcentaje que no va seguido de dos dígitos hexadecimales, como un 100% al final o un %zz. Es un problema de sintaxis, y la lectura estricta lo rechaza y dice dónde está, mientras que la lectura permisiva lo conserva como texto literal y lo enumera. El segundo es un escape cuyo byte es perfectamente legal pero cuyos bytes no forman un carácter UTF-8 válido, como un %FF suelto o un carácter de tres bytes cortado como %E4%B8. Eso no es un problema de sintaxis, así que ambas lecturas devuelven el texto, sustituyen los bytes que no se pueden decodificar por el carácter de reemplazo U+FFFD («�») y muestran una advertencia que lo indica. Esa advertencia es la parte útil: un texto que llega con caracteres de reemplazo suele significar que el remitente usó otro juego de caracteres, o que la cadena se escapó una vez de más. La codificación porcentual nombra bytes, y esta página, como el estándar de URL, siempre lee esos bytes como UTF-8.

«¿Qué no hace esta página?»

No divide una URL en esquema, host, ruta y consulta — para eso está el Analizador de URL. No comprueba si un enlace es seguro de abrir, no contacta con nada, y no adivina el juego de caracteres de los bytes que hay detrás de un escape: siempre los lee como UTF-8, que es lo que exige el estándar de URL.

«¿Qué alternativa necesita la decodificación, y cómo sé que es correcta?»

Pulse Autocomprobación. Compara los codificadores propios de la página con encodeURIComponent, encodeURI y URLSearchParams de la plataforma para cada carácter ASCII imprimible, vuelve a ejecutar cada ejemplo de las tablas de arriba, vuelve a comprobar las cadenas de capas registradas, y después informa del número de comprobaciones aquí.

Estándares y alcance

La codificación porcentual está especificada en la RFC 3986, sección 2.1, con la definición de caracteres reservados y no reservados en las secciones 2.2 y 2.3, y la regla de mayúsculas en la sección 6.2.2.1. Los conjuntos que usa realmente un navegador al construir una URL están en el Estándar URL de WHATWG, que los divide por contexto: un conjunto para el fragmento, otro para la consulta, otro para la consulta especial, otro para la ruta, otro para la información de usuario, y el más estrecho para un componente individual. El envío de formularios, incluido el signo más, está en el Estándar HTML bajo application/x-www-form-urlencoded. Las dos funciones encodeURI y encodeURIComponent forman parte del propio ECMAScript.

Esta página rellena las columnas de ruta, consulta y fragmento a partir de sus propios conjuntos por contexto, e imprime la lista exacta de cada contexto junto al resultado. Esos conjuntos derivan de los de WHATWG y difieren de ellos en dos puntos deliberados: un hash se escapa dentro de una consulta, porque un hash sin escapar empezaría el fragmento, y el conjunto de componentes se fija exactamente a los caracteres que escapa encodeURIComponent. Cuando una función de la plataforma es la definición de la respuesta — encodeURIComponent, encodeURI y la serialización de formularios — esa función se llama directamente, así que esas columnas son el comportamiento propio del navegador y no una reimplementación.

El texto de la página se escribió para este sitio. Cada valor de las tablas de arriba lo produce el propio código de la página al cargarse, y se verificó contra las implementaciones de la plataforma con las herramientas de prueba de este sitio; la Autocomprobación repite esa comparación en su navegador.