Tomcat servlet response关于中文乱码的经验

前言

最近修改老项目项目,使用zuul网关返回的中文内容乱码了,如果使用GBK或者GB2312编码确正常显示,稍微实验了一下,发现里面很多细节,毕竟Springboot对我们做了很多事情,而且当我们使用不同的模式会出现很多神奇的现象。

准备

因为是zuul网关,实际上是servlet的response回写返回结果,直接模拟如下:效果相同

@RestController
@SpringBootApplication
public class Main {
    public static void main(String[] args) {
        SpringApplication.run(Main.class, args);
    }

    @GetMapping("/hello")
    public void stringDemo(HttpServletResponse response) throws IOException {
        //response.setCharacterEncoding("UTF-8");
        try(PrintWriter printWriter = response.getWriter()){
            printWriter.write("中文");
            printWriter.flush();
        }
    }
}

模拟返回,执行postman和浏览器访问:

 

都是乱码无疑。 

原因

原因实际上很简单,response默认编码为ISO8859-1,我们实际来看看

 

所以除了英文,都是乱码,Springboot默认实际上已经utf-8编码了,在ResponseBody注解上

 要解决这个问题,可以手动编码

但是新问题出现了

 

postman处理正常,但是浏览器都是乱码,说明浏览器不能正确识别http的response编码

如果我们使用GBK或者GB2312

 

只有浏览器正确显示,其他包括浏览器的console都乱码,说明浏览器识别中文是gbk或者GB2312等,但是其他地方并不是这么识别的。 

Springboot解决思路

上面的思路在postman或者接口发钱调用是可以正确识别中文的,那么有没有response默认utf-8呢,Springboot实际上是默认utf-8,只不过没启用。

org.springframework.web.filter.CharacterEncodingFilter

在org.springframework.boot.autoconfigure.web.servlet.HttpEncodingAutoConfiguration自动装配的bean中被初始化

 

 那么配置是server.servlet.encoding.forceResponse

去掉手动编码,加上配置

 

跟手动设置utf-8编码一样,实际上也是如此

 

mime

实际上上面没有找到根本原因,只是修修补补,本质的原因是mime的缘故,刚刚的请求没有mime的设置,从F12工具看,响应mime.types实际上没有默认值

postman也是如此,只不过postman在没有mime时中文默认utf-8编码,浏览器对于中文是gbk或者gb2312,当然可能有其他中文编码,只不过笔者没有试完。

那么怎么处理呢,如果使用Springboot,那么默认就可以使用ResponseBody注解,通过切面打上mime-type,现在我们手动加上试试

结果如下:

 

mime-type定义了数据的格式,即:http请求和返回的内容格式

在Tomcat和spring-web里面有详细的定义,当然我们也可以自定义,毕竟就是内容的格式罢了,火狐上有关于mime的简介:

 

总结

实际上这个问题很简单,而且也很容易解决,只不过不同的软件有不同的标准,所以即使是utf-8并不能解决问题,而是需要根据实际的情况,比如http,根据mime-type明显比指定utf-8更能表达具体的意义,毕竟mime是具体的标准。