编码将内存字节作用于磁盘文件或者网络文件的过程,是将磁盘文件/网络文件 反解析成内存字节的过程.
这个过程中如果 内存字符串到 “字节数组”的编码 与 网络/磁盘文件的之间转化的编解码方式不一致或者不兼容就 会产生乱码.
写文件的正常流程:内存字符串->“使用编码转化为(1)”-> 字节数组 ,writer将字节数组写入文件,文件头中的编码方式如果和 字符串转化为字节数组的编码不一致或者不兼容,打开文件/再次使用文件头中的编码方式读取文件的时候就会显示乱码, 这个时候方式处理是: 如果明确知道(1)中使用的编码,那么打开文件或者读取文件主动指定(1)中使用的编码。
上面讲了乱码的原理性,在判断乱码的时候需要考虑输入源的编码是什么,输出源使用了什么编码 , 下面看几个乱码的例子.
现象不再赘述
理论上浏览器发送请求的时候,指定编码 并使用指定的编码编码request param或者body 那么后端只要使用浏览器说的编码来 解码就能得到正确内容.
排查方式为 确认request header中的编码方式 与后端接收到并且解码的编码方式是否一致,可以使用抓包的方式判断。如果request header中没有指定编码方式,那么就看浏览器以及服务端的默认编码方式了, 所以在协议交互的过程中编码方式是最好显示指定
现象不再赘述
理论上后端返回response的时候会在response header中带上编码方式,并使用指定的编码方式编码response body 那么浏览器只要使用response header中的编码来 解码就能得到正确内容.
排查方式为 确认response header中的编码方式,了解不同浏览器的默认编码逻辑. 以及html中的其他元素标签对编码的支持
public enum OfcDeliveryStatusEnum {
init(0, "数据库-初始化"),
create(1, "生成运单"),
accept(2, "配送待分配")
private Integer code;
private String desc;
}
现象:当在代码中想要使用OfcDeliveryStatusEnum.create.getDesc()的时候 发现获取到的是乱码
原因:java源文件是UTF-8格式保存的,maven编译使用的GBK格式编译生产class文件,这中间有一个文件读取到内存再输出到文件的过程,编码的差异导致格式被破坏从而产生乱码.
排查方式需要明白java的工作原理,OfcDeliveryStatusEnum.create.getDesc() 程序运行起来后直接从内存的metaspace中取出来的,如果内存中通过utf-8查看是乱码,那么内存中已经乱码了,而内存值是通过加载class文件生成的,那么class文件难道也是乱码吗?class文件是maven从java源文件编译而来,源文件正常,那只可能是编译过程出了问题
现象不再赘述
应用程序连接mysql server之间有一次通信会话写入数据,mysql server到 存储到磁盘有一次文件存储,从mysqlserver 查询数据返回到前端有一次通信会话 可以看到这中间有3次通信,那就存在三次编码转化,分别抓住两次编码转化是否一致。
1)character_set_server:mysql server默认字符集。
2)character_set_database:数据库默认字符集。
3)character_set_client:MySQL server假定客户端发送的查询使用的字符集。
4)character_set_connection:MySQL Server接收客户端发布的查询请求后,将其转换为character_set_connection变量指定的字符集。
5)character_set_results:mysql server把结果集和错误信息转换为character_set_results指定的字符集,并发送给客户端。
6)character_set_system:系统元数据(字段名等)字符集
https://help.aliyun.com/document_detail/169436.html
不管什么场景,只要存在一次读写操作,如果使用的编码不一致就可能导致乱码, 现实中碰到的场景都可能使用多次读写操作的复合场景,判断乱码的方式需要分段判断,最终确认第一次出现编码不一致的一段