Estoy usando Java 11 con Tomcat 9 con la última JSP / JSTL. Estoy probando en Chrome 71 y Firefox 64.0 en Windows 10. Tengo el siguiente documento de prueba:
<%@ page contentType="text/html; charset=UTF-8" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!DOCTYPE html>
<html lang="en-US">
<head>
<meta charset="UTF-8"/>
<title>Hello</title>
</head>
<body>
<c:if test="${not empty param.fullName}">
<p>Hello, ${param.fullName}.</p>
</c:if>
<form>
<div>
<label>Full name: <input name="fullName" /></label>
</div>
<button>Say Hello</button>
</form>
</body>
</html>
Esta es quizás la forma más simple posible. Como ya saben los formularios method
de forma predeterminada get
, la forma action
por defecto ""
(enviar a la misma página), y de la forma enctype
por defecto application/x-www-form-urlencoded
.
Si entro en el nombre de "José Flávio" (un famoso cantante de forró brasileño y músico) en el campo y presento, el formulario se envía a través de HTTP GET
a la misma página utilizando hello.jsp?fullName=Fl%C3%A1vio+Jos%C3%A9
. Esto es correcto, y la página dice:
Hello, Flávio José.
Si cambio la forma method
de post
e introduzca el mismo nombre "Flávio José", el contenido del formulario se presentaron en su lugar por medio POST
, con contenidos HTTP de solicitud:
fullName=Fl%C3%A1vio+Jos%C3%A9
Esto también parece correcta. Pero esta vez la página dice:
Hello, Flávio José.
En lugar de ver %C3%A
como una secuencia de octects UTF-8, JSP parece pensar que se trata de una serie de ISO-8859-1 octetos (o página de códigos 1252 octetos), y por lo tanto se les decodificando a la secuencia de caracteres incorrecto.
Pero ¿dónde está recibiendo ISO-8859-1? ¿Cuál es mi página JSP para indicar que carece de la codificación correcta?
Voy a señalar también que la especificación WHATWG dice que application/x-www-form-urlencoded
octetos deben ser analizados como UTF-8 por omisión. Es la especificación servlet de Java simplemente rota? ¿Cómo trabajo alrededor de esto?
Esto es causado por Tomcat, pero la raíz del problema es la especificación de Java Servlet 4, que es incorrecta y obsoleta.
Originalmente HTML 4.0.1 dijo que application/x-www-form-urlencoded
octetos codificados deben ser decodificados como US-ASCII . La especificación servlet cambiado esto para decir que, si no se especifica la solicitud de codificación, los octetos deben ser decodificados como ISO-8859-1. Tomcat simplemente está siguiendo la especificación servlet.
Hay dos problemas con la especificación de servlets Java. La primera es que la interpretación moderna de application/x-www-form-urlencoded
es que los octetos codificados deben ser decodificados con UTF-8 . El segundo problema es que atar el octeto de decodificación para el conjunto de caracteres de recursos confunde dos niveles de decodificación.
Echar otro vistazo a este POST
contenido:
fullName=Fl%C3%A1vio+Jos%C3%A9
Se dará cuenta de que es ASCII !! No importa si se considera la POST
petición HTTP juego de caracteres a ser ISO-8859-1
, UTF-8
o US-ASCII
-Ya lo todavía terminan con exactamente los mismos caracteres Unicode antes de decodificar los octetos! Qué codificación se utiliza para decodificar los octetos que codifican está completamente separada.
Como otro ejemplo, digamos que se descarga un archivo de texto instructions.txt
que está claramente marcado como ISO-8859-1, y contiene el URI https://example.com/example.jsp?fullName=Fl%C3%A1vio+Jos%C3%A9
. El hecho de que el archivo de texto tiene un juego de caracteres ISO-8859-1
, ¿significa que es necesario decodificar %C3%A
usando la norma ISO-8859-1? ¡Por supuesto no! El conjunto de caracteres utilizado para decodificar caracteres URI es un nivel separado de decodificación en la parte superior del juego de caracteres de recursos tipo de contenido ! Del mismo modo los octects de valores codificados en application/x-www-form-urlencoded
deben ser decodificados usando UTF-8, independientemente de la charset subyacente del recurso.
Hay varias soluciones, algunos de ellos encontraron a encontrar buscando en el carácter Tomcat codificación de Preguntas al "uso de UTF-8 en todas partes" .
Establecer la codificación de caracteres solicitud en su web.xml
archivo.
Añadir lo siguiente a su WEB-INF/web.xml
archivo:
<request-character-encoding>UTF-8</request-character-encoding>
Este ajuste es agnóstico de la aplicación contenedor servlet, y se define adelante en la especificación servlet. (Debe ser capaz de poner alternativamente en Tomcat de conf/web.xml
archivo, si quieres un entorno global y no le importa cambiar la configuración de Tomcat).
Ajuste el SetCharacterEncodingFilter
en su web.xml
archivo.
Tomcat tiene un equivalente de propiedad: utilizar el org.apache.catalina.filters.SetCharacterEncodingFilter
en el WEB-INF/web.xml
archivo, como el Tomcat FAQ anterior menciona, y como se ilustra por https://stackoverflow.com/a/37833977/421049 , un extracto a continuación:
<filter>
<filter-name>setCharacterEncodingFilter</filter-name>
<filter-class>org.apache.catalina.filters.SetCharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>setCharacterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Esto hará que su aplicación web única obra en Tomcat, por lo que es mejor poner esto en la instalación de Tomcat conf/web.xml
archivo en lugar, como el post anterior menciona. De hecho de Tomcat conf/web.xml
instalaciones tienen estas dos secciones, pero comentado; simplemente descomentarlas y deben funcionar las cosas.
Forzar el carácter solicitud de codificación UTF-8 en la JSP o servlet.
Puede forzar la codificación de caracteres de la petición de servlet a UTF-8, en algún lugar temprano en la JSP:
<% request.setCharacterEncoding("UTF-8"); %>
Pero eso es feo, difícil de manejar y propenso a errores, y va en contra de las prácticas modernas mejores scriptles-JSP no debe utilizarse más.
Con suerte podemos conseguir una especificación de servlets de Java más reciente para eliminar cualquier relación entre el juego de caracteres de recursos y la decodificación de application/x-www-form-urlencoded
octetos, y simplemente estado que application/x-www-form-urlencoded
octetos deben ser decodificados como UTF-8, como es la práctica moderna como aclara la última W3C y las especificaciones WHATWG.
Actualización: He actualizado el Tomcat FAQ en caracteres problemas de codificación con esta información.