项目场景:
最近参与一个老项目浏览器兼容工作,因为微软停止对万恶的IE进行维护,项目不得不兼容其他浏览器,这个过程中不断踩坑。心里把IE骂了一万遍了。而且这老项目本地没法运行,只能修改以后在测试环境中调试,所以没办法在后端代码断点调试。我们戏称为“盲改”。
问题描述:
在最近的修改中发现了一个问题,其中一个GET请求的参数包含中文,IE浏览器直接报400错误。为了解决这个错误以"IE浏览器get请求URL包含中文400"为关键字进行百度,解决问题过程中踩了很多坑,所以解决花时间研究一下编码问题。
原因分析:
IE、Firefox、Chrome浏览器对URL的处理各不相同,浏览器在传输URl时得对URL进行编码,IE默认是以UTF-8来传输 的,Firefox肯定不是以UTF-8来编码,有可能是以ISO-8859-1来编码的,而Chrome好像是采用的GBK来编码。说白了就是IE直接传中文导致错误!!!!
谷歌浏览器请求截图:
解法分析:
Tip:由于项目代码不宜直接截图发文,所以下面的解决过程在本地复现环境测试截图!!
踩坑方案
上面说过,遇到问题后直接百度了,然后就看了一堆文章,发现了一个方法,不知道是因为项目环境的原因还是,我成功踩坑了!!!!
//前端使用encodeURI对中文进行编码
const url = "http://localhost:8080/demo_code/demo?remarks=" + encodeURI(remarks);
//后端对应的对中文参数解码
String remarks = request.getParameter("remarks");
String remarks = java.net.URLDecoder.decode(remarks, "UTF-8");
//这里转GBK是因为项目整个就是GBK编码
remarks = new String(remarks.getBytes("ISO-8859-1"), "GBK");
我直接对着这个代码一通改,结果直接踩坑,一起看看改完以后的效果吧。
改完以后的不得不吐槽了一句:什么玩意文章!乱发的嘛,想想可能是我自己的操作有问题,对,一定是这样的。所以就继续百度,发现大多数都是这么解决的问题,那一定是我的问题了吧。所以我决定索性花点时间来研究研究乱码问题。下面先把解决方法丢出来,赶时间的直接看这个。
解决方案
乱码主要是因为服务器输出的字符串的编码和客户端显示字符串的编码不一致。所以我们只需要设置服务器和客户端的编码相同就可以解决这个问题。
解决办法就是我们在前端使用两次encodeURI对中文参数进行编码,至于为什么参照了不少博客。下面这两个讲的很好。
前端 encodeURI 为什么要编码两次
encodeURI来解决URL传递时为什么需要进行两次encodeURI编码
我个人的理解就是前端第一次encodeURI看做使用UTF-8第一次编码,这时候汉字成了%E6%B5%8B%E8%AF%95,这时候进行第二次encodeURI时虽然又使用UTF-8编码了一次,但是字符串还是%E6%B5%8B%E8%AF%95,因为英文字符的UTF-8编码和ISO-8859-1编码其实是一样的。这么理解后,我们前端的编码可以理解为。
//get请求字符串
const url = "http://localhost:8080/demo_code/demo?remarks=" + encodeURI(encodeURI(remarks));
后端解码,因为我们的项目环境使用的是Tomcat8以下版本,所以默认的编码方式为IS0-8859-1,也就是说服务器在从URL中取出参数时会使用ISO-8859-1进行一次解码,也就是说我们的request.getParameter取到的参数是已经进行了一次ISO-8859-1解码的参数。我们需要对这个参数再进行一次UTF-8解码即可复原。
//获取数据,服务器ISO-8859-1解码一次
String remarks = request.getParameter("remarks");
System.out.println("获取到的原始参数:" + remarks);
//数据解码
remarks = URLDecoder.decode(remarks,"UTF-8");
System.out.println("最终的参数:" + remarks);
再度踩坑
改到这里的时候本来信息满满,觉得自己已经拿捏了这个问题,但是结果呢,请看。
后来仔细看了代码发现,虽然我们后端解析正常了,但是数据在回显的时候编码还是不对,也就是我们少了这么两句。
//告诉浏览器输出的内容是xml,并且以GBK的编码来查看这个内容。
response.setContentType("text/xml; charset=GBK");
//设置服务器输出的编码为GBK
response.setCharacterEncoding("GBK");
主要是因为服务器输出的字符串的编码和客户端显示字符串的编码不一致。导致乱码问题。所以我们只需要设置服务器和客户端的编码相同就可以解决这个问题。
解决问题
总结
历经磨难终于解决了乱码问题,后面准备继续研究Java Web的编码问题,计划出一期编码问题详解,但愿代码再无乱码。
作者:专业bug开发
时间:2022年8月22日11:30:26