I ran into a problem where our Spring MVC claims to return data in UTF-8 but it actually uses ISO-8859-1 when accessed using a browser. The server reports the encoding correctly when the HTTP request doesn't have the Accept header (or if it is present but has no value) but not when the header is present and has a value. I'd like the server to both report and use UTF-8. There are workarounds but I'm wondering if our server is incorrectly configured.
I have this example controller:
Now I open up Konsole, set its encoding to ISO-8859-1 and type in bash: (formatted a bit for clarity):Code:import java.io.IOException; import java.io.OutputStream; import javax.servlet.http.HttpServletResponse; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; @Controller public class TestController { @RequestMapping("/logintest") public @ResponseBody String test() { return "-ä-語-"; } @RequestMapping("/logintest2") public void test2(HttpServletResponse response) throws IOException { OutputStream os = response.getOutputStream(); byte[] content = "-ä-語-".getBytes(); os.write(content); response.setContentType("text/html; charset=UTF-8"); response.setContentLength(content.length); } }
The server responds that it's serving content-type foo/bar (which is funny, but I think unrelated) in encoding UTF-8. However, since the 'ä' character is just one character and not two and my terminal encoding is ISO-8859-1, it looks like the server's claimed and actual encoding conflict. This is confirmed by the fact that the content-length is 5, not 8. Furthermore, if I pipe the output to a file and open it using a hex editor, I see that the 'ä' character has hex value E4, just like in ISO-8859-1.> echo "GET /app/logintest HTTP/1.1
Host: localhost:8080
Accept: foo/bar
" | nc localhost 8080
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: foo/bar;charset=UTF-8
Content-Length: 5
Date: Thu, 13 Oct 2011 11:49:50 GMT
-ä-?-
On the other hand, if I omit the Accept header from the request...
This is better since now the server at least reports the encoding correctly, though ISO-8859-1 doesn't support Chinese characters. (The same happens if the Accept header is present but has no value, i.e. "Accept: ")> echo "GET /app/logintest HTTP/1.1
Host: localhost:8080
" | nc localhost 8080
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/plain;charset=ISO-8859-1
Content-Length: 5
Date: Thu, 13 Oct 2011 11:52:14 GMT
-ä-?-
As a comparison, logintest2 returns data using the correct encoding:
> echo "GET /app/logintest2 HTTP/1.1
Host: localhost:8080
Accept: foo/bar
" | nc localhost 8080
HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Content-Type: text/html;charset=UTF-8
Content-Length: 8
Date: Thu, 13 Oct 2011 11:59:20 GMT
-ä-èª-
After finding out there's a problem I wanted to figure out if there's a problem with our server's configuration. I cd'ed to the directory of our project to search for xml files that define something related to encodings. I used search terms a bit more general than what I expected to find, e.g. iso-8859 instead of iso-8859-1. I typed:
These didn't find anything. On the other hand,Code:> grep -i iso-8859 $(find -name \*.xml) > grep -i iso8859 $(find -name \*.xml) > grep -i windows-125 $(find -name \*.xml) > grep -i latin $(find -name \*.xml)returned three hits (plus some unrelated ones):Code:> grep -i 'utf' $(find -name \*.xml)|grep -v '^./target' | grep -v '<?xml version'
web.xml has:
spring-context.xml has:Code:<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>
./pom.xml has:Code:<bean id="viewResolver" class="org.springframework.web.servlet.view.freemarker.FreeMarkerViewResolver"> <property name="cache" value="true"/> <property name="prefix" value=""/> <property name="suffix" value=".ftl"/> <property name="requestContextAttribute" value="request"/> <property name="contentType" value="text/html;charset=UTF-8"></property> </bean>
As pointed out in other places, CharacterEncodingFilter shouldn't have anything to do with this since it relates to HTTP requests, not responses. ViewResolver seems to apply only to files with suffix .ftl (we use those to create ModelAndView objects), but here we're just returning data directly without FreeMarker templates. The last hit seems to define the source file encoding, which is fine since I'm able to hard-code Chinese characters into the source.Code:<properties> <org.springframework.version>3.0.5.RELEASE</org.springframework.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties>
There are some other posts over the web that seem related, with various workarounds.
The post Spring MVC response encoding issue seems to describe the same issue.
The forum post Cannot set character encoding using @ResponseBody and HttpMessageConverter may describe the same problem.
The forum post @ResponseBody and UTF-8 seems to describe the same problem but some of the anwers seem to answer a different question: how to set the charset reported by the server.
The forum post Can not change response Charset encoding, it is always set to ISO-8859-1 describes a problem where the server reports ISO-8859-1 as the response encoding. In my case the server reports the encoding I'd like but it doesn't actually use it.
The bug report @ResponseBody doesn't obey CharacterEncodingFilter seems to be related to setting the reported encoding (not the actually used one).
I'm running my project in SpringSource Tool Suite 2.7.2. My project has Maven dependencies to files with names such as spring-web-3.0.5.RELEASE.jar, so I assume my Spring Framework is version 3.0.5. The server type is "VMware vFabric tc Server v2.5,2.6". I'm using Kubuntu Linux 11.04.
(For the next two weeks I may not be able to follow this thread actively. My colleagues may, however.)


Reply With Quote
