In the environment I'm using (Tomcat 6), percent sequences in path segments apparently are decoded using ISO-8859-1 when being mapped to a @PathVariable.
I'd like that to be UTF-8.
I already configured Tomcat to use UTF-8 (using the URIEncoding attribute in server.xml).
Is Spring/Rest doing the decoding on its own? If yes, where can I override the default encoding?
Additional information; here's my test code:
@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 );
}
If I do an HTTP GET request with the following URI path:
/TEST/enc/%c2%a3%20and%20%e2%82%ac%20rates
which is the UTF-8 encoded then percent-encoded form of
/TEST/enc/£ and € rates
the output that I get is:
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
which to me shows that Tomcat (after setting the URIEncoding attribute) does the right thing (see getPathInfo()), but the path variable is decoded still in ISO-8859-1.
And the answer is:
Spring/Rest apparently uses the request encoding, which is a very strange thing to do, as this is about the body, not the URI. Sigh.
Adding this:
<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>
fixed the problem. It really should be simpler.
And actually, it's worse:
If the method indeed has a request body, and that one isn't encoded in UTF-8, the additional forceEncoding parameter is needed. This seems to work, but I'm concerned it will cause more problems later on.
Another approach
In the meantime, I found out that it's possible to disable the decoding, my specifying
<property name="urlDecode" value="false"/>
...in which case the recipient can to the right thing; but of course this will make lots of other things harder.
The @PathVariable annotation is used to extract the value of the template variables and assign their value to a method variable. A Spring controller method to process above example is shown below; @RequestMapping("/users/{userid}", method=RequestMethod.
@PathVariable is a Spring annotation which indicates that a method parameter should be bound to a URI template variable. If the method parameter is Map<String, String> then the map is populated with all path variable names and values. It has the following optional elements: name - name of the path variable to bind to.
The @PathVariable annotation is used to extract the value from the URI. It is most suitable for the RESTful web service where the URL contains some value. Spring MVC allows us to use multiple @PathVariable annotations in the same method. A path variable is a critical part of creating rest resources.
Using @PathVariable required attribute 3 version, @PathVariable annotation has required attribute, to specify it is mandatorily required in URI. The default value for this attribute is true if we make this attribute value to false, then Spring MVC will not throw an exception.
I thing that you need add filter to 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>
The path variable is still decoded in ISO-8859-1 for me, even with the Character Encoding Filter. Here is what I had to do to get around this. Please let me know if you have any other ideas!
To see the actual UTF-8 decoded characters on the server, you can just do this and take a look at the value (you need to add "HttpServletRequest httpServletRequest" to your controller parameters):
String requestURI = httpServletRequest.getRequestURI();
String decodedURI = URLDecoder.decode(requestURI, "UTF-8");
I can then do whatever I want (like get the parameter manually from the decoded URI), now that I have the right decoded data on the server.
Try to configure connector on Tomcat in server.xml.
Add useBodyEncodingForURI="true"
or URIEncoding="UTF-8"
to your Connector tag.
For example:
<Connector port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
useBodyEncodingForURI="true"
redirectPort="8443" />
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With