2010-12-17 16 views
23

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.Spring/Rest @PathVariable codificación de caracteres

Me gustaría que fuera UTF-8.

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

¿Spring/Rest hace la decodificación por sí mismo? En caso afirmativo, ¿dónde puedo anular la codificación predeterminada?

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

@RequestMapping(value = "/enc/{foo}", method = RequestMethod.GET) 
public HttpEntity<String> 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<String>(resp, headers); 
} 

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

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

que es la codificación UTF-8 a continuación, forma de

/TEST/enc/£ and € rates 
ciento codificados

la salida que consigo 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 

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:

Primavera/Resto aparentemente utiliza la codificación solicitud, que es una cosa muy extraña que hacer, ya que esto es sobre el cuerpo , no el URI. Suspiro.

La adición de este:

<filter> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
    <init-param> 
     <param-name>encoding</param-name> 
     <param-value>UTF-8</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 

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

Y, de hecho, es peor:

Si el método de hecho tiene un cuerpo de la petición, y que uno 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, he descubierto que es posible desactivar la decodificación, mi especificando

<property name="urlDecode" value="false"/> 

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

Respuesta

27

I cosa que usted necesita agregar el filtro a web.xml

<filter> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> 
    <init-param> 
     <param-name>encoding</param-name> 
     <param-value>UTF-8</param-value> 
    </init-param> 
    <init-param> 
     <param-name>forceEncoding</param-name> 
     <param-value>true</param-value> 
    </init-param> 
</filter> 
<filter-mapping> 
    <filter-name>CharacterEncodingFilter</filter-name> 
    <url-pattern>/*</url-pattern> 
</filter-mapping> 
+1

Esto suena bien en teoría, pero no parece ayudar. Mirando los documentos, si aplica la codificación para el * cuerpo *, no el URI. –

+1

@Julian: Esta es una solución correcta (aunque 'forceEncoding' no es necesario), Spring utiliza la codificación de solicitud para resolver las variables de ruta, vea http://static.springsource.org/spring/docs/3.0.x/javadoc-api /org/springframework/web/util/UrlPathHelper.html (y también necesita este filtro para los parámetros POST de todos modos). – axtavt

+1

@axtavt: oh mi, ¿a quién se le ocurren diseños como este? De todos modos, he podido confirmar que recibo UTF-8 cuando envío una solicitud HTTP con un cuerpo codificado UTF-8, como POST. No * he * podido hacer que el filtro funcione según lo anunciado (sé que algo está sucediendo porque cuando rompo el nombre de clase, obtengo una excepción ClassNotFoundException). –

4

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

Para ver la UTF-8 real decodificado caracteres en el servidor, sólo puede hacer esto y echar un vistazo al valor (es necesario añadir "HttpServletRequest HTTPServletRequest" a sus parámetros de regulación):

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

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

+3

Asegúrese de que la asignación de URL de su servlet de envío no sea más corta que CharacterEncodingFilter, de lo contrario, ni siquiera llegará al filtro. – checketts

+0

¡Ese era el problema! ¡Gracias! – 11101101b

0

¿Pero no es una lástima que tenga que meterse con la configuración de Tomcat (URIEncoding) para hacer todo esto? 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 descodificación 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 sus amigos. Aparentemente no lo hacen, lo que significa que no puede tener @RequestParam o @PathVariable capturar algo que no sea nosotros-ascii cadenas de forma segura sin depender de la configuración del contenedor de servlets.

2

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

<Connector port="8080" protocol="HTTP/1.1" 
      connectionTimeout="20000" 
      useBodyEncodingForURI="true" 
      redirectPort="8443" /> 
Cuestiones relacionadas