前两天遇到了一个前台富文本保存异常的问题,具体表现为前台编辑好的富文本保存后再次查看会发现每一行的缩进都变成了 ? ,页面显示非常糟糕,寻求解决的办法。
bug背景
- 项目前台采用了ext组件提供的富文本编辑框(老项目的无奈)
- 文件在进入java处理之前经过了基于antisamy框架的防xss攻击filter
- 数据库为oracle,页面编码格式为UTF-8
解决过程
debug模式逐步跟进bug,追踪缩进在哪一步变成?乱码。最开始怀疑是页面格式没有严格限定为UTF-8,导致数据库不能识别。结果发现两点异常:
1.数据库有正常存储的空格;
2.断点跟进发现前台信息在进入java存储代码时已经变成了?
也就是说,问题很可能出在antisamy框架上。
然后我把debug的断点打到了filter里,request传入时,显示正常。出filter时,就不正常了。那只好把断点跟进了框架里,最终发现异常出现在执行了antisamy框架对输入进行decode,也就是说decode()方法将缩进变成了空格。
下一步就是求助搜索引擎了。以下内容来自网络:
在UTF-8编码和ASCII码中,空格都对应0x20,但在UTF-8不是所有的空格都会被认为是0x20,有一种空格宽度不会被压缩,这种不会被压缩的空格对应的字节码是“0xC2 0xA0”。
缩进就是一种宽度不会被压缩的空格,也就是说缩进对应的字节码就是”0xC2 0xA0”。
由于在GB2312等其他编码中并不存在”0xC2 0xA0”,直接使用decode()进行编码转换,这个字符就会被替换为”ox3F”,对应的就是半角问号。
解决办法
知道问题原因再去解决就比较简单了,我们只需要在得到UTF-8字符的时候进行一个字符串的替换,将缩进变为标准空格,就可以解决问题。但是要注意,由于这个空格用于排版,我们再进行替换的时候,要根据富文本编辑插件的显示效果尝试插入几个空格会正常显示。替换代码如下:
byte bytes[] = {(byte) 0xC2,(byte) 0xA0};
String UTFSpace = new String(bytes,"utf-8");
html = html.replaceAll(UTFSpace, " ");