汉字传值奇数乱码问题解决策略, 转码编码解码

这两天写一个项目遇到一个很怪异的现象,就是在url中汉字传值,如果是奇数个汉字则出现编码错误。先说下环境:

 

前台页面试gb2312编码,后台的filter是gbk,web server是nginx+resin,nginx用的是操作系统编码,编码是gbk

 

在输入http://www.我的域名.com/search/searchByName.action?query=%C1%AC%C1%AC%BF%B4   (1)

时后台不需要做处理,返回字符串正常

 

再输入http://www.我的域名.com/search/searchByName.action?query=连连看                                      (2)

时后台就显示乱码

 

我分别用chrome、firefox、ie8做了测试,结果虽然是乱码还各有特色

 

最初,在网上搜索解决方案,不过大部分都是一个来源,也就是让你在页面上先对汉字url encode一下然后再传值,但是这种情况不符合我的需求,我是要在浏览器中直接输入url,汉字传值;

 

解决方案一,在nginx中配置,将传递过来的url进行重写,让参数以重叠的方式向后台传送,比如原来是"query=你好啊",重写为"query = 你好啊你好啊",这样可以避免奇数个乱码问题,不过这有一个问题,就是和web server的耦合性太高,只要有汉字传值,就得重写nginx配置文件,不可取。

 

解决方案二,在后台发现,取出的parameter在utf8转换成gbk时,如果字符串.getbytes()是奇数个,最后一个byte会被吞掉,信息损失了,就没法转换回来了。很烦人,这时候在同事的启发下,发现request.getQueryString(),也可以得到参数,并且都是被转码过的,形如“query=%e7%be%8e%e5%a5%b3”,这个是没有被gbk过滤的,所以就通过处理这个字符串获取到了没有信息损失的编码。不过这时还有个问题,页面输入(1)(2)两个链接时后台要拿到相同的汉字,但是他们被编码后显示的编码值却不同,就是这个时候只要通过判断是否为utf8的url(此时有汉字传值),如下代码:

 

String parameterString = request.getQueryString();
		if(parameterString!=null&&!parameterString.equals("")){
			try {
				CharTools ct = new CharTools();
				if(ct.isUtf8Url(parameterString)){
					parameterString = URLDecoder.decode(parameterString, "utf-8");
				}else{
					parameterString = URLDecoder.decode(parameterString, "gbk");
				}
			} catch (UnsupportedEncodingException e) {
				logger.info("url解码出错", e);
			}
			String[] parameters = parameterString.split("&");
			for(String str : parameters){
				if(str.indexOf("query=")!=-1){
					query = str.substring(str.indexOf("=")+1);
				}
			}
		}

 

 其中对应的CharTools中的方法为:

 

public boolean isUtf8Url(String text) {
        text = text.toLowerCase();
        int p = text.indexOf("%");
        if (p != -1 && text.length() - p > 9) {
            text = text.substring(p, p + 9);
        }
        return Utf8codeCheck(text);
    }
 private boolean Utf8codeCheck(String text) {
        String sign = "";
        if (text.startsWith("%e"))
            for (int i = 0, p = 0; p != -1; i++) {
                p = text.indexOf("%", p);
                if (p != -1)
                    p++;
                sign += p;
            }
        return sign.equals("147-1");
    }
 

 

这样就可以将不同的编码传过来的url,进行不同的处置

 

next

 

这时候本以为完事大吉,没想又出了新的问题,即:在ie下汉字传值还是乱码,我通过后台检测发现,ie的request.getQueryString(),获取的是“query=????”,汉字没有以编码后的形式传送过来,然后再检查request.getParameter("query"),发现是正常的,这时候就可以通过对发送到后台的客户端就行判断,如下:

 

String agent = request.getHeader("User-Agent");
if(agent.indexOf("MSIE")!=-1){//ie情况比较特殊,不过此时在parameters中是正常的
			query =  request.getParameter("query");
}

 这样在ie下拿到的汉字也就可以正常的显示了。

 

 

解决方案三:觉得最好的解决方案还是写个filter,现在项目比较紧张,以后要写,这样就可以忽略掉具体的请求,从整体层次进行解决问题。大致思路就是将方案二的解决办法浓缩到filter中。以后再写

 

还有一些感想,觉得chrome也不是那么完美,汉字传值不自动转码,给开发造成不少麻烦,还是firefox比较强大~

你可能感兴趣的:(java,编码解码)