2010-12-17 18 views
23

W środowisku, którego używam (Tomcat 6), sekwencje procentowe w segmentach ścieżek najwyraźniej są dekodowane przy użyciu ISO-8859-1 podczas mapowania do zmiennej @PathVariable.Spring/Rest @PathVariable kodowanie znaków

Chciałbym, żeby to było UTF-8.

Już skonfigurowałem Tomcat do korzystania z UTF-8 (przy użyciu atrybutu URIEncoding w pliku server.xml).

Czy Spring/Rest wykonuje samodzielnie dekodowanie? Jeśli tak, to gdzie mogę nadpisać domyślne kodowanie?

Dodatkowe informacje; tu jest mój kodu testu:

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

Jeśli zrobić żądania HTTP GET z następującej ścieżce URI:

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

która jest kodowanie UTF-8 wtedy procent kodowane formę

/TEST/enc/£ and € rates 

Dane wyjściowe, które otrzymuję to:

 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 

co do mnie pokazuje, że Tomcat (po ustawieniu atrybutu URIEncoding) robi właściwą rzecz (zobacz getPathInfo()), ale zmienna ścieżki jest dekodowana jeszcze w ISO-8859-1.

A odpowiedź jest:

Wiosna/Reszta najwyraźniej wykorzystuje kodowanie żądania, co jest bardzo dziwne rzeczą do zrobienia, ponieważ jest to temat ciała, a nie URI. Westchnienie.

Dodanie tego:

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

rozwiązaniu problemu. To naprawdę powinno być prostsze.

I rzeczywiście, to gorzej:

Jeśli metoda rzeczywiście ma ciała żądanie, i że nie jest kodowany w UTF-8, potrzebny jest dodatkowy parametr forceEncoding. To wydaje się działać, ale obawiam się, że spowoduje to później więcej problemów.

Innym podejściem

W międzyczasie okazało się, że jest to możliwe, aby wyłączyć dekodowanie, mój określając

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

... w takim przypadku odbiorca może do słuszne; ale oczywiście spowoduje to wiele innych rzeczy trudniejszych.

Odpowiedz

27

I rzeczą, którą trzeba dodać filtr do 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

To brzmi dobrze w teorii, ale nie pomaga. Patrząc na dokumenty, jeśli wymusza kodowanie * body *, a nie URI. –

+1

@Julian: To jest właściwe rozwiązanie (chociaż 'forceEncoding' nie jest konieczne), Spring używa kodowania żądań do rozwiązania zmiennych ścieżek, patrz http://static.springsource.org/spring/docs/3.0.x/javadoc-api /org/springframework/web/util/UrlPathHelper.html (i tak samo potrzebujesz tego filtru dla parametrów POST). – axtavt

+1

@axtavt: oh my, kto wymyśla takie projekty? W każdym razie, byłem w stanie potwierdzić, że rzeczywiście otrzymuję kodowanie UTF-8, gdy wysyłam żądanie HTTP z treścią kodowaną w UTF-8, taką jak POST. * Nie * udało mi się przekonać działającego filtru (wiem, że coś się dzieje, ponieważ po złamaniu nazwy klasy otrzymuję wyjątek ClassNotFoundException). –

4

Zmienna droga nadal jest dekodowany w ISO-8859-1 dla mnie, nawet z filtrem kodowanie znaków.Oto, co musiałem zrobić, aby ominąć to. Daj mi znać, jeśli masz jakieś inne pomysły!

Aby zobaczyć rzeczywisty UTF-8 dekodowane znaków na serwerze, można po prostu to zrobić i spojrzeć na wartości (trzeba dodać „HttpServletRequest HttpServletRequest” do parametrów regulatora):

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

Mogę wtedy zrobić, co chcę (np. Pobrać parametr ręcznie z odkodowanego URI), teraz, gdy mam odpowiednie zdekodowane dane na serwerze.

+3

Upewnij się, że mapowanie adresów URL serwletu wysyłki nie jest krótsze niż parametr CharacterEncodingFilter, w przeciwnym razie nawet nie trafi w filtr. – checketts

+0

To był problem! Dzięki! – 11101101b

0

Ale czy to nie ssać, że musisz w ogóle zadzierać z konfiguracją Tomcat (URIEncoding), aby to zadziałało? Jeśli API serwletu zapewnił sposób uzyskania ścieżki i parametrów żądania w ich nierozpoznanej reprezentacji, aplikacja (lub Spring) mogłaby całkowicie sam sobie poradzić z dekodowaniem. I najwyraźniej, HttpServletRequest#getPathInfo i HttpServletRequest#getQueryString nawet by to dostarczyły, ale dla tego ostatniego oznaczałoby to, że Spring musiałaby analizować i dekodować sam ciąg zapytania i nie polegać na HttpServletRequest#getParameter i znajomych. Najwyraźniej nie robią tego, co oznacza, że ​​nie można przechwycić niczego innego poza ciągami znaków ascii w bezpieczny sposób, bez polegania na konfiguracji kontenera serwletów.

2

Spróbuj skonfigurować konektor na serwerze Tomcat w pliku server.xml. Dodaj useBodyEncodingForURI="true" lub URIEncoding="UTF-8" do swojego znacznika Connector. Na przykład:

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