Codificación de caracteres Spring / Rest @PathVariable

En el entorno que estoy usando (Tomcat 6), las secuencias porcentuales en segmentos de ruta aparentemente se decodifican utilizando ISO-8859-1 cuando se asignan a @PathVariable.

Me gustaría que fuera UTF-8.

Ya configuré Tomcat para usar UTF-8 (usando el atributo URIEncoding en server.xml).

¿Spring / Rest está haciendo la deencoding por sí mismo? En caso afirmativo, ¿dónde puedo anular la encoding predeterminada?

Información Adicional; aquí está mi código de prueba:

@RequestMapping( value = "/enc/{foo}", method = RequestMethod.GET ) public HttpEntity enc( @PathVariable( "foo" ) String foo, HttpServletRequest req ) { String resp; resp = " path variable foo: " + foo + "\n" + " req.getPathInfo(): " + req.getPathInfo() + "\n" + "req.getPathTranslated(): " + req.getPathTranslated() + "\n" + " req.getRequestURI(): " + req.getRequestURI() + "\n" + " req.getContextPath(): " + req.getContextPath() + "\n"; HttpHeaders headers = new HttpHeaders(); headers.setContentType( new MediaType( "text", "plain", Charset.forName( "UTF-8" ) ) ); return new HttpEntity( resp, headers ); } 

Si realizo una solicitud HTTP GET con la siguiente ruta URI:

 /TEST/enc/%c2%a3%20and%20%e2%82%ac%20rates 

que es la forma codificada por UTF-8 luego codificada en porcentajes

 /TEST/enc/£ and € rates 

el resultado que obtengo es:

  path variable foo: £ and ⬠rates req.getPathInfo(): /enc/£ and € rates req.getPathTranslated(): C:\Users\jre\workspace\.metadata\.plugins\org.eclipse.wst.server.core\tmp0\wtpwebapps\TEST\enc\£ and € rates req.getRequestURI(): /TEST/enc/%C2%A3%20and%20%E2%82%AC%20rates req.getContextPath(): /TEST 

lo que para mí muestra que Tomcat (después de configurar el atributo URIEncoding) hace lo correcto (ver getPathInfo ()), pero la variable de ruta se decodifica aún en ISO-8859-1.

Y la respuesta es :

Spring / Rest aparentemente usa la encoding de solicitud, lo cual es algo muy extraño de hacer, ya que se trata del cuerpo , no del URI. Suspiro.

Agregando esto:

  CharacterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter  encoding UTF-8    CharacterEncodingFilter /*  

arregló el problema Realmente debería ser más simple.

Y en realidad, es peor:

Si el método tiene realmente un cuerpo de solicitud, y ese no está codificado en UTF-8, se necesita el parámetro forceEncoding adicional. Esto parece funcionar, pero me preocupa que cause más problemas más adelante.

Otro enfoque

Mientras tanto, descubrí que es posible desactivar la deencoding, mi especificación

  

… en cuyo caso el destinatario puede hacer lo correcto ; pero, por supuesto, esto hará que muchas otras cosas sean más difíciles.

Creo que necesitas agregar filtro a web.xml

  CharacterEncodingFilter org.springframework.web.filter.CharacterEncodingFilter  encoding UTF-8   forceEncoding true    CharacterEncodingFilter /*  

La variable de ruta aún se decodifica en ISO-8859-1 para mí, incluso con el filtro de encoding de caracteres. Esto es lo que tuve que hacer para evitar esto. Por favor, avíseme si tiene otras ideas.

Para ver los caracteres decodificados UTF-8 reales en el servidor, puede hacer esto y echar un vistazo al valor (debe agregar “HttpServletRequest httpServletRequest” a los parámetros de su controlador):

 String requestURI = httpServletRequest.getRequestURI(); String decodedURI = URLDecoder.decode(requestURI, "UTF-8"); 

Entonces puedo hacer lo que quiera (como obtener el parámetro manualmente del URI descodificado), ahora que tengo los datos decodificados correctos en el servidor.

Intenta configurar el conector en Tomcat en server.xml. Agregue useBodyEncodingForURI="true" o URIEncoding="UTF-8" a su etiqueta de Connector. Por ejemplo:

   

Pero ¿no es una lástima que tenga que meterse con la configuración de Tomcat (URIEncoding) para hacer que esto funcione? Si la API de servlet proporciona una forma de obtener la ruta y solicitar parámetros en su representación no codificada, la aplicación (o Spring) podría tratar la desencoding por sí misma. Y aparentemente, HttpServletRequest#getPathInfo y HttpServletRequest#getQueryString incluso proporcionarían esto, pero para este último esto significaría que Spring tendría que analizar y decodificar la cadena de consulta en sí misma y no confiar en HttpServletRequest#getParameter y friends. Aparentemente no lo hacen, lo que significa que no puede tener @RequestParam o @PathVariable capturando algo que no sea nosotros-ascii cadenas de forma segura sin depender de la configuración del contenedor de servlets.