前言
最近修改老项目项目,使用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是具体的标准。