Saltar al contenido

HTML: el formulario no envía entradas en formato UTF-8

Hola, encontramos la solución a tu pregunta, continúa leyendo y la verás más abajo.

Solución:

Agregué el meta etiqueta: nada ha cambiado.

De hecho, no tiene ningún efecto cuando la página se sirve a través de HTTP en lugar de, por ejemplo, desde el sistema de archivos del disco local (es decir, la URL de la página es http://... en lugar de por ejemplo file://...). En HTTP, se utilizará el juego de caracteres en el encabezado de respuesta HTTP. Ya lo ha configurado de la siguiente manera:

<%@page pageEncoding="UTF-8"%>

Esto no solo escribirá la respuesta HTTP usando UTF-8, sino que también establecerá el charset atributo en el Content-Type encabezado de respuesta.

Este será utilizado por el navegador web para interpretar la respuesta y codificar cualquier parámetro de formulario HTML.


Agregué el accept-charset atributo en form : nada ha cambiado.

Solo tiene efecto en el navegador Microsoft Internet Explorer. Incluso entonces lo está haciendo mal. Nunca lo use. En su lugar, todos los navegadores web reales utilizarán charset atributo especificado en el Content-Type encabezado de la respuesta. Incluso MSIE lo hará de la manera correcta siempre que tú lo hagas no especifica el accept-charset atributo. Como se dijo antes, ya lo ha configurado correctamente a través de pageEncoding.


Deshazte de ambos meta etiqueta y accept-charset atributo. No tienen ningún efecto útil y solo te confundirán a largo plazo e incluso empeorarán las cosas cuando el usuario final use MSIE. Solo adhiérete a pageEncoding. En lugar de repetir el pageEncoding en todas las páginas JSP, también puede configurarlo globalmente en web.xml como a continuación:


    
        *.jsp
        UTF-8
    

Como se dijo, esto le dirá al motor JSP que escriba la salida de respuesta HTTP usando UTF-8 y la establezca también en el encabezado de respuesta HTTP. El navegador web utilizará el mismo juego de caracteres para codificar los parámetros de la solicitud HTTP antes de enviar de vuelta al servidor.

El único paso que falta es decirle al servidor que debe usar UTF-8 para decodificar los parámetros de solicitud HTTP antes de regresar getParameterXxx() llamadas. La forma de hacerlo globalmente depende del método de solicitud HTTP. Dado que está utilizando el método POST, esto es relativamente fácil de lograr con la siguiente clase de filtro de servlet que se engancha automáticamente en todas las solicitudes:

@WebFilter("/*")
public class CharacterEncodingFilter implements Filter 

    @Override
    public void init(FilterConfig config) throws ServletException 
        // NOOP.
    

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException 
        request.setCharacterEncoding("UTF-8");
        chain.doFilter(request, response);
    

    @Override
    public void destroy() 
        // NOOP.
    

Eso es todo. En Servlet 3.0+ (Tomcat 7 y más reciente) no necesita más web.xml configuración.

Solo debes tener en cuenta que es muy importante que setCharacterEncoding() se llama al método antes de los parámetros de la solicitud POST se obtienen por primera vez utilizando cualquiera de getParameterXxx() métodos. Esto se debe a que se analizan solo una vez en el primer acceso y luego se almacenan en caché en la memoria del servidor.

Entonces, por ejemplo, la siguiente secuencia es incorrecto:

String foo = request.getParameter("foo"); // Wrong encoding.
// ...
request.setCharacterEncoding("UTF-8"); // Attempt to set it.
String bar = request.getParameter("bar"); // STILL wrong encoding!

Haciendo el setCharacterEncoding() El trabajo en un filtro de servlet garantizará que se ejecute a tiempo (al menos, antes de cualquier servlet).


En caso de que desee indicarle al servidor que decodifique los parámetros de solicitud GET (no POST) usando UTF-8 también (esos parámetros que ve después ? carácter en la URL, ya sabe), entonces básicamente necesitaría configurarlo en el extremo del servidor. No es posible configurarlo a través de la API de servlet. En caso de que esté utilizando, por ejemplo, Tomcat como servidor, entonces es cuestión de agregar URIEncoding="UTF-8" atributo en elemento propio de Tomcat /conf/server.xml.

En caso de que todavía vea Mojibake en la salida de la consola de System.out.println() llamadas, es muy probable que la salida estándar no esté configurada para usar UTF-8. La forma de hacerlo depende de quién sea responsable de interpretar y presentar el stdout. En caso de que esté utilizando, por ejemplo, Eclipse como IDE, entonces es una cuestión de configuración Ventana> Preferencias> General> Espacio de trabajo> Codificación de archivos de texto a UTF-8.

Ver también:

  • Unicode: ¿cómo conseguir los caracteres correctos?

Calentamiento

Permítanme comenzar diciendo el hecho universal de que todos sabemos que la computadora no entiende nada más que bits: ceros y unos.

Ahora, cuando está enviando un formulario HTML a través de HTTP y los valores viajan por el cable para llegar al servidor de destino, entonces esencialmente se pasan una gran cantidad de bits: 0 y 1.

  • Antes de enviar los datos al servidor, el cliente HTTP (navegador o curl, etc.) los codificará usando algún esquema de codificación y espera que el servidor los decodifique usando el mismo esquema para que el servidor sepa exactamente qué cliente ha enviado.
  • Antes de enviar la respuesta al cliente, el servidor la codificará usando algún esquema de codificación y espera que el cliente la decodifique usando el mismo esquema para que el cliente sepa exactamente qué servidor ha enviado.

Un analogía porque esto puede ser: le estoy enviando una carta y le digo si está escrita en inglés, francés u holandés, para que reciba el mensaje exacto que tenía la intención de enviarle. Y mientras me responde, también mencionará en qué idioma debo leer.

Importante para llevar Es que el hecho de que cuando los datos salgan del cliente se codificarán y se decodificarán en el lado del servidor, y viceversa. Si no especifica nada, el contenido se codificará según la aplicación / x-www-form-urlencoded antes de salir del lado del cliente al lado del servidor.

Concepto principal

El calentamiento de lectura es importante. Hay un par de cosas que necesita para asegurarse de obtener los resultados esperados.

  • Tener configurada la codificación correcta antes de enviar datos del cliente al servidor.
  • Tener la decodificación y codificación correctas configuradas en el lado del servidor para leer la solicitud y escribir la respuesta al cliente (esta fue la razón por la que no estaba obteniendo los resultados esperados)
  • Asegúrese de que en todas partes se use el mismo esquema de codificación, no debería suceder que en el cliente esté codificando usando ISO-8859-1 y en el servidor esté decodificando usando UTF-8, de lo contrario habrá errores (por mi analogía, te escribo en inglés y estás leyendo en francés)
  • Tener configurada la codificación correcta para su visor de registros, si intenta verificar usando el registro usando la línea de comandos de Windows o el visor de registros de Eclipse, etc. (Este fue un motivo que contribuyó a su problema, pero no fue el motivo principal porque, en primer lugar, los datos leídos del objeto de solicitud no se decodificaron correctamente. La codificación del visor de registros de Windows cmd o Eclipse también es importante, lea aquí)

Tener configurada la codificación correcta antes de enviar datos del cliente al servidor

Para garantizar esto, se habla de varias formas, pero diré que use el campo HTTP Accept-Charset request-header. De acuerdo con el fragmento de código proporcionado, ya lo está usando y usándolo correctamente, por lo que es bueno desde ese frente.

Hay gente que dirá que no usa esto o no está implementado pero yo muy humildemente no estoy de acuerdo con ellos. Accept-Charset es parte de la especificación HTTP 1.1 (He proporcionado un enlace) y el navegador que implementa HTTP 1.1 implementará lo mismo. También pueden argumentar que usan el atributo “charset” del campo Accept request-header pero

  • Realmente no está presente, verifique el enlace del campo Aceptar solicitud-encabezado que proporcioné.
  • Mira esto

Le proporciono todos los datos y hechos, no solo palabras, pero aún así, si no está satisfecho, realice las siguientes pruebas con diferentes navegadores.

  • Colocar accept-charset="ISO-8859-1" en su formulario HTML y en el formulario POST / GET con caracteres chinos o franceses avanzados en el servidor.
  • En el servidor, decodifica los datos usando el esquema UTF-8.
  • Ahora repita la misma prueba intercambiando la codificación de cliente y servidor.

Verá que ninguna de las veces pudo ver los caracteres esperados en el servidor. Pero si usa el mismo esquema de codificación, verá el carácter esperado. Entonces, los navegadores implementan accept-charset y su efecto se activa.

Tener la decodificación y codificación correctas configuradas en el lado del servidor para leer la solicitud y escribir la respuesta al cliente

Se habla de muchas formas de las que puedes hacer para lograr esto (en algún momento, es posible que se requiera alguna configuración en función de un escenario específico, pero a continuación se resuelve el 95% de los casos y también se aplica a su caso). Por ejemplo:

  1. Utilice el filtro de codificación de caracteres para configurar la codificación a petición y respuesta.
  2. Usar setCharacterEncoding a petición y respuesta
  3. Configure el servidor web o de aplicaciones para la codificación de caracteres correcta utilizando -Dfile.encoding=utf8 etc. Leer más aquí
  4. Etc.

Mi favorito es el primero y también resolverá su problema: “Filtro de codificación de caracteres”, debido a las siguientes razones:

  • Toda la lógica de manejo de codificación está en un solo lugar.
  • Tienes todo el poder a través de la configuración, cambia en un solo lugar y todos están contentos.
  • No debe preocuparse de que algún otro código pueda leer mi secuencia de solicitud o eliminar la secuencia de respuesta antes de que pueda configurar la codificación de caracteres.

1. Filtro de codificación de caracteres

Puede hacer lo siguiente para implementar su propio filtro de codificación de caracteres. Si está utilizando algún marco como Springs, etc., entonces no necesita escribir su propia clase, solo hacer la configuración en web.xml

La lógica central a continuación es muy similar a lo que hace Spring, aparte de mucha dependencia, lo que hace consciente de los frijoles.

web.xml (configuración)


    EncodingFilter
    
        com.sks.hagrawal.EncodingFilter
    
    
        encoding
        UTF-8
    
    
        forceEncoding
        true
    



    EncodingFilter
    /*

EncodingFilter (clase de implementación de codificación de caracteres)

public class EncodingFilter implements Filter 
    private String encoding = "UTF-8";
    private boolean forceEncoding = false;

    public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException 
        request.setCharacterEncoding(encoding);
        if(forceEncoding) //If force encoding is set then it means that set response stream encoding as well ...
            response.setCharacterEncoding(encoding);
        
        filterChain.doFilter(request, response);
    

    public void init(FilterConfig filterConfig) throws ServletException 
        String encodingParam = filterConfig.getInitParameter("encoding");
        String forceEncoding = filterConfig.getInitParameter("forceEncoding");
        if (encodingParam != null) 
            encoding = encodingParam;
        
        if (forceEncoding != null) 
            this.forceEncoding = Boolean.valueOf(forceEncoding);
        
    

    @Override
    public void destroy() 
        // TODO Auto-generated method stub

    

2. ServletRequest.setCharacterEncoding ()

Este es esencialmente el mismo código que se hace en el filtro de codificación de caracteres, pero en lugar de hacerlo en el filtro, lo está haciendo en su servlet o clase de controlador.

La idea es de nuevo para usar request.setCharacterEncoding("UTF-8"); para configurar la codificación del flujo de solicitudes http antes de comenzar a leer el flujo de solicitudes http.

Pruebe el siguiente código y verá que si no está utilizando algún tipo de filtro para establecer la codificación en el objeto de solicitud, el primer registro será NULO mientras que el segundo registro será “UTF-8”.

System.out.println("CharacterEncoding = " + request.getCharacterEncoding());
request.setCharacterEncoding("UTF-8");
System.out.println("CharacterEncoding = " + request.getCharacterEncoding());

A continuación se muestra un extracto importante de los documentos de Java setCharacterEncoding. Otra cosa a tener en cuenta es que debe proporcionar un esquema de codificación válido, de lo contrario obtendrá UnsupportedEncodingException

Anulaciones el nombre de la codificación de caracteres utilizada en el cuerpo de esta solicitud. Este método se debe llamar antes de leer los parámetros de solicitud o leer la entrada usando getReader (). De lo contrario, no tiene ningún efecto.

Siempre que sea necesario, he hecho todo lo posible para proporcionarle enlaces oficiales o respuestas de recompensas aceptadas por StackOverflow, para que pueda generar confianza.

Según su salida publicada, parece que el parámetro se envía como UTF8 y luego los bytes Unicode de la cadena se interpretan como ISO-8859-1.

El siguiente fragmento demuestra su comportamiento observado

String eGrave = "u00E8"; // the letter è
System.out.printf("letter UTF8      : %s%n", eGrave);
byte[] bytes = eGrave.getBytes(StandardCharsets.UTF_8);
System.out.printf("UTF-8 hex        : %X %X%n",
        bytes[0], bytes[1], bytes[0], bytes[1]
);
System.out.printf("letter ISO-8859-1: %s%n",
        new String(bytes, StandardCharsets.ISO_8859_1)
);

producción

letter UTF8      : è
UTF-8 hex        : C3 A8
letter ISO-8859-1: è

Para mi el formulario envía el datos codificados en UTF8 correctos, pero posteriormente estos datos no se tratan como UTF8.

editar Algunos otros puntos para probar:

generar la codificación de caracteres que tiene su solicitud

System.out.println(request.getCharacterEncoding())

forzar el uso de UTF-8 para recuperar el parámetro (no probado, solo una idea)

request.setCharacterEncoding("UTF-8");
... request.getParameter(...);

Puntuaciones y comentarios

¡Haz clic para puntuar esta entrada!
(Votos: 2 Promedio: 3.5)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *