先解释下几个相关的接口:
/** * 表示 HTTP 请求消息和响应消息的基本接口 * 可以通过 getHeaders() 获取相应的 HttpHeaders */ public interface HttpMessage { /** * 返回消息头(请求头/响应头) */ HttpHeaders getHeaders(); } /** * 对 HTTP 响应消息的抽象 */ public interface HttpOutputMessage extends HttpMessage { /** * 以 OutputStream 返回消息体 */ OutputStream getBody() throws IOException; } /** * 对 HTTP 请求消息的抽象 */ public interface HttpInputMessage extends HttpMessage { /** * 以 InputStream 返回消息体 */ InputStream getBody() throws IOException; }说白了,HttpInputMessage与HttpOutputMessage 是 SpringMVC 对请求消息和响应消息对抽象。
在 SpringMVC 中 请求消息和响应消息的最终实现就是ServletServerHttpRequest以及ServletServerHttpResponse。这两个实现类又分别封装有HttpServletRequest以及HttpServletResponse。 Servlet容器如Tomcat将请求和响应封装为HttpServletRequest/HttpServletResponse,然后传递给使用者。
public class CharacterEncodingFilter extends OncePerRequestFilter { @Nullable private String encoding; private boolean forceRequestEncoding = false; private boolean forceResponseEncoding = false; public CharacterEncodingFilter() { } public CharacterEncodingFilter(String encoding) { this(encoding, false); } public CharacterEncodingFilter(String encoding, boolean forceEncoding) { this(encoding, forceEncoding, forceEncoding); } public CharacterEncodingFilter(String encoding, boolean forceRequestEncoding, boolean forceResponseEncoding) { Assert.hasLength(encoding, "Encoding must not be empty"); this.encoding = encoding; this.forceRequestEncoding = forceRequestEncoding; this.forceResponseEncoding = forceResponseEncoding; } public void setEncoding(@Nullable String encoding) { this.encoding = encoding; } @Nullable public String getEncoding() { return this.encoding; } public void setForceEncoding(boolean forceEncoding) { this.forceRequestEncoding = forceEncoding; this.forceResponseEncoding = forceEncoding; } public void setForceRequestEncoding(boolean forceRequestEncoding) { this.forceRequestEncoding = forceRequestEncoding; } public boolean isForceRequestEncoding() { return this.forceRequestEncoding; } public void setForceResponseEncoding(boolean forceResponseEncoding) { this.forceResponseEncoding = forceResponseEncoding; } public boolean isForceResponseEncoding() { return this.forceResponseEncoding; } @Override protected void doFilterInternal( HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String encoding = getEncoding(); if (encoding != null) { if (isForceRequestEncoding() || request.getCharacterEncoding() == null) { request.setCharacterEncoding(encoding); } if (isForceResponseEncoding()) { response.setCharacterEncoding(encoding); } } filterChain.doFilter(request, response); } }
CharacterEncodingFilter 作为一个Filter,用来设置请求和响应的编码。 在 servlet 容器中 Filter 优先于 servlet 的执行。 那么在 SpringMVC 中 Filter 也会优先于 HandlerInterceptor 以及 Controller 的执行。
而一般的 HttpMessageConverter 只会去操作 HttpIntputMessage 以及HttpOutputMessage 里的getBody()方法返回的 InputStream 以及 OutputStream。
那么,返回给浏览器的字符编码将会由SpringMVC(HttpMessageConverter)指定。 对于HttpMessageConverter一般都会有默认的编码(ISO-8859-1),所以CharacterEncodingFilter指定的编码在以下代码中被覆盖了。
CharacterEncodingFilter 这个东东用在纯 Servlet 中还是很不错的。在 Spring 中使用就有些鸡肋了。=。= 同时 HttpServletResponse 需要设置 “ContentType”response.setContentType("text/plain");,否则 setCharacterEncoding 并不会起作用。
如上,Jetty 实现的getCharacterEncoding会首先在_contentType字段中读取。
