web-dev-qa-db-fra.com

Spring/Rest @PathVariable encoding

Dans l'environnement que j'utilise (Tomcat 6), les séquences de pourcentage dans les segments de chemin d'accès sont apparemment décodées à l'aide d'ISO-8859-1 lorsqu'elles sont mappées sur une variable @PathVariable.

J'aimerais que ce soit UTF-8.

J'ai déjà configuré Tomcat pour qu'il utilise UTF-8 (à l'aide de l'attribut URIEncoding dans server.xml).

Est-ce que Spring/Rest fait le décodage seul? Si oui, où puis-je remplacer le codage par défaut?

Information additionnelle; voici mon code de test:

@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 je fais une requête HTTP GET avec le chemin d'URI suivant:

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

qui est la forme UTF-8 codée puis codée en pourcentage de

/TEST/enc/£ and € rates

le résultat que je reçois est:

      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

ce qui pour moi montre que Tomcat (après avoir défini l'attribut URIEncoding) fait ce qu'il faut (voir getPathInfo ()), mais la variable de chemin est décodée dans ISO-8859-1.

Et la réponse est:

Spring/Rest utilise apparemment le codage de la requête, ce qui est une chose très étrange à faire, car il s'agit du body, pas de l'URI. Soupir.

Ajoutant ceci:

<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>

résolu le problème. Cela devrait vraiment être plus simple.

Et en fait, c'est pire:

Si la méthode a effectivement un corps de requête et que celui-ci n'est pas codé en UTF-8, le paramètre supplémentaire forceEncoding est nécessaire. Cela semble fonctionner, mais je crains que cela ne causera plus de problèmes plus tard.

Une autre approche

En attendant, j'ai découvert qu'il est possible de désactiver le décodage, ma spécification

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

... auquel cas le destinataire peut accéder à la bonne chose; mais bien sûr, cela rendra beaucoup d'autres choses plus difficiles.

25
Julian Reschke

Je pense que vous devez ajouter un filtre à 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>
27
Hurda

La variable de chemin est toujours décodée dans ISO-8859-1, même avec le filtre de codage de caractères. Voici ce que je devais faire pour résoudre ce problème. S'il vous plaît laissez-moi savoir si vous avez d'autres idées!

Pour voir les caractères décodés UTF-8 réels sur le serveur, vous pouvez simplement le faire et consulter la valeur (vous devez ajouter "HttpServletRequest httpServletRequest" aux paramètres de votre contrôleur):

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

Je peux alors faire ce que je veux (comme obtenir le paramètre manuellement à partir de l'URI décodé), maintenant que j'ai les données décodées appropriées sur le serveur.

4
11101101b

Essayez de configurer le connecteur sur Tomcat dans server.xml . Ajoutez useBodyEncodingForURI="true" ou URIEncoding="UTF-8" à votre balise Connector . Par exemple:

    <Connector port="8080" protocol="HTTP/1.1"
           connectionTimeout="20000"
           useBodyEncodingForURI="true"
           redirectPort="8443" />
3
Avseiytsev Dmitriy

Mais ne craignez-vous pas de devoir jouer avec la configuration de Tomcat (URIEncoding) pour que cela fonctionne? Si l'API de servlet offrait un moyen d'obtenir le chemin et les paramètres de demande dans leur représentation non décodée, l'application (ou Spring) pourrait gérer le décodage entièrement par elle-même. Et apparemment, HttpServletRequest#getPathInfo et HttpServletRequest#getQueryString fourniraient même cela, mais pour le dernier cela signifierait que Spring devrait analyser et décoder la chaîne de requête elle-même et ne pas s'appuyer sur HttpServletRequest#getParameter et ses amis. Apparemment, ils ne le font pas, ce qui signifie que vous ne pouvez pas avoir @RequestParam ou @PathVariable capturer autre chose que des chaînes us-ascii sans vous fier à la configuration du conteneur de servlet.

0
Olaf Klischat