2010-12-17 6 views
23

In der Umgebung, die ich verwende (Tomcat 6), werden prozentuale Sequenzen in Pfadsegmenten offenbar mit ISO-8859-1 decodiert, wenn sie einer @PathVariable zugeordnet werden.Spring/Rest @PathVariable Zeichencodierung

Ich möchte das UTF-8 sein.

Ich habe Tomcat bereits für die Verwendung von UTF-8 konfiguriert (mit dem URIncoding-Attribut in server.xml).

Macht Spring/Rest die Decodierung für sich alleine? Wenn ja, wo kann ich die Standardcodierung überschreiben?

Zusätzliche Informationen; hier ist mein Testcode:

@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); 
} 

Wenn ich eine HTTP-GET-Anforderung mit dem folgenden URI-Pfad:

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

, die die UTF-8 codierten dann Prozent-kodierte Form von

/TEST/enc/£ and € rates 

die Ausgabe, die ich erhalte, ist:

 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 

Das zeigt mir, dass Tomcat (nach dem Setzen des URIncoding-Attributs) das Richtige tut (siehe getPathInfo()), aber die Pfadvariable wird noch in ISO-8859-1 dekodiert.

Und die Antwort ist:

Frühling/Rest nutzt offenbar die Anfrage Codierung, die eine sehr seltsame Sache zu tun, da dies über den Körper ist, nicht der URI. Seufzer.

das Hinzufügen von:

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

das Problem behoben. Es sollte wirklich einfacher sein.

Und tatsächlich, es ist schlimmer:

Wenn die Methode in die Tat hat eine Anfrage Körper, und dass man nicht in UTF-8, die zusätzlichen forceEncoding Parameter codiert wird benötigt. Dies scheint zu funktionieren, aber ich bin besorgt, es wird später mehr Probleme verursachen.

Ein anderer Ansatz

In der Zwischenzeit fand ich heraus, dass es möglich ist, die Decodierung zu deaktivieren, meine Angabe

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

... in diesem Fall kann der Empfänger auf die Richtige; aber das wird natürlich viele andere Dinge schwieriger machen.

Antwort

27

ich, was Sie Filter benötigen hinzufügen

<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

Das klingt in der Theorie gut, aber scheint nicht zu helfen. Wenn Sie die Dokumente überprüfen, wird die Codierung für den * body * und nicht für den URI erzwungen. –

+1

@Julian: Dies ist eine richtige Lösung (obwohl 'forceEncoding' nicht erforderlich ist), verwendet Spring die Anforderungscodierung zum Auflösen von Pfadvariablen, siehe http://static.springsource.org/spring/docs/3.0.x/javadoc-api /org/springframework/web/util/UrlPathHelper.html (und Sie benötigen diesen Filter auch für POST-Parameter). – axtavt

+1

@axtavt: Oh mein Gott, wer kommt mit solchen Designs? Wie auch immer, ich konnte bestätigen, dass ich tatsächlich UTF-8 bekomme, wenn ich eine HTTP-Anfrage mit einer UTF-8-kodierten Nachricht, wie zB POST, sende. Ich bin * nicht * in der Lage gewesen, den Filter funktionierend wie angekündigt zu bekommen (ich weiß, dass etwas passiert, weil, wenn ich den Klassennamen breche, ich eine ClassNotFoundException erhalte). –

4

Der Pfad-Variable web.xml noch in ISO-8859-1 für mich decodiert wird, auch mit der Zeichenkodierung Filter.Hier ist, was ich tun musste, um dies zu umgehen. Bitte lassen Sie mich wissen, wenn Sie andere Ideen haben!

Um die tatsächliche UTF-8 decodiert Zeichen auf dem Server zu sehen, können Sie dies nur tun, und einen Blick auf den Wert nehmen (man braucht „HttpServletRequest HttpServletRequest“, um Ihre Reglerparameter hinzugefügt werden):

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

Ich kann dann tun, was ich will (wie den Parameter manuell aus dem decodierten URI holen), jetzt, da ich die richtigen decodierten Daten auf dem Server habe.

+3

Stellen Sie sicher, dass die URL-Zuordnung Ihres Versandservlets nicht kürzer ist als der CharacterEncodingFilter, andernfalls wird der Filter nicht einmal getroffen. – checketts

+0

Das war das Problem! Vielen Dank! – 11101101b

0

Aber ist es nicht scheiße, dass Sie sich mit der Tomcat-Konfiguration (URIEncoding) herumschlagen müssen, damit dies funktioniert? Wenn die Servlet-API eine Möglichkeit zum Abrufen der Pfad- und Anforderungsparameter in ihrer nicht decodierten Darstellung bietet, könnte die Anwendung (oder Spring) die Dekodierung vollständig eigenständig durchführen. Und anscheinend würden HttpServletRequest#getPathInfo und HttpServletRequest#getQueryString sogar dies bereitstellen, aber für letzteres würde dies bedeuten, dass Spring die Abfragezeichenfolge analysieren und decodieren müsste und sich nicht auf HttpServletRequest#getParameter und Freunde verlassen müsste. Anscheinend tun sie das nicht, was bedeutet, dass Sie @RequestParam oder @PathVariable nichts anderes als uns-ascii-Zeichenfolgen erfassen können, ohne sich auf die Konfiguration des Servlet-Containers verlassen zu müssen.

2

Versuchen Sie, den Connector auf Tomcat in server.xml zu konfigurieren. Fügen Sie Ihrem Connector-Tag useBodyEncodingForURI="true" oder URIEncoding="UTF-8" hinzu. Zum Beispiel:

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