深入剖析tomcat容器的乱码问题

http的本质还是socket,所以底层传输的还是字节流(不要深究到二进制层面),既然是字节流,那么肯定会涉及到编码和解码.

乱码的原因大家肯定都知道,也很简单,那就是编码和解码的格式不一致
既然知道了根源,那么我们是否能从这个角度来解决问题?是的,只要你保证前台编码和后台解码的格式一样的时候,就肯定不会出现乱码了。

 

下面要用到一些例子,这里先给出程序:

 

index.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=gbk">
<title>Insert title here</title>
<script type="text/javascript">
	function loadFunction()
	{
		var url = "encodingServlet?name=";
		url += encodeURI("严");
		document.getElementById("name").href = url + "&d=" + new Date();
	}
	
	function escapeCode()
	{
		alert(encodeURI("严"))
	}
</script>
</head>
<body οnlοad="loadFunction()">
<a id="name">name</a>

<form action="encodingServlet" method="get">
	<input type="text" name="name"/>
	<input type="submit" text="submit"/>
</form>

<button οnclick="escapeCode()">aaa</button>
<br>
<a href="encodingServlet?name=严">aaaa</a>
</body>
</html>

 首先看前台编码的几种情况:


1.首先最常见的就是你在地址栏直接输入一个地址
比如:https://www.google.com/webhp?hl=en&tab=ww#hl=en&tbo=d&output=search&sclient=psy-ab&q=你好&oq=你好
非常不幸,这种情况下你根本无法控制浏览器如何对你输入的内容进行编码。我使用英文版的IE进行测试,它使用的是ISO-8859-1格式,而英文版的FireFox使用的是UTF-8。
这种情况就不讨论了,google也会因为这种原因而导致乱码,不过我相信大家总是会有办法解决的。(怎么解决请教我一下)

 

 

2.网页里面的一个超链接
比如:上面index.jsp中的<a href="encodingServlet?name=严">aaaa</a>
那么这个时候前台的编码是以

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

里面的pageEncoding决定的

 

3.FORM表单
无论get方式还是post方式都是以

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>

里面的charset决定的

 

4.encodeURI函数
该函数将参数中的字符将转换成UTF-8编码方式的byte数组,并使用十六进制转义序列(%xx)生成替换。

过程用Java模拟如下:

 

byte[] data1 = "严".getBytes("UTF-8");
		String result = "";
		for(byte datai : data1)
		{
			result += "%" + Integer.toHexString(datai >= 0 ? datai : datai + 256);
		}
 

再来看看后台是如何解码的:

 

我们都是通过request.getParameter("name");这样的语句来得到参数的,

在我们调用这个方法的时候tomcat容器会自动帮我们做一次解码,请看下面的tomcat部分源码(解析参数):

该方法位于:org.apache.catalina.util.RequestUtil

 

public static void parseParameters(Map map, byte[] data, String encoding)
        throws UnsupportedEncodingException {

        if (data != null && data.length > 0) {
            int    ix = 0;
            int    ox = 0;
            String key = null;
            String value = null;
            while (ix < data.length) {
                byte c = data[ix++];
                switch ((char) c) {
                case '&':
                    value = new String(data, 0, ox, encoding);
                    if (key != null) {
                        putMapEntry(map, key, value);
                        key = null;
                    }
                    ox = 0;
                    break;
                case '=':
                    if (key == null) {
                        key = new String(data, 0, ox, encoding);
                        ox = 0;
                    } else {
                        data[ox++] = c;
                    }                   
                    break;  
                case '+':
                    data[ox++] = (byte)' ';
                    break;
                case '%':
                    data[ox++] = (byte)((convertHexDigit(data[ix++]) << 4)
                                    + convertHexDigit(data[ix++]));
                    break;
                default:
                    data[ox++] = c;
                }
            }
            //The last value does not end in '&'.  So save it now.
            if (key != null) {
                value = new String(data, 0, ox, encoding);
                putMapEntry(map, key, value);
            }
        }

    }
 

可以看到,这个方法会要求输入编码格式encoding,那么这个参数是怎么得到的呢。

它分为两种情况,如果下面两种情况你都没有设置,就会采用ISO-8859-1的格式来解码:

 

1.参数位于URL中,也就是通过GET的方式请求,这个encoding请在tomcat的连接器中配置,也就是server.xml中的
<Connector connectionTimeout="20000" port="9180" protocol="HTTP/1.1" redirectPort="8443" URIEncoding="UTF-8"/>
加入了URIEncoding="UTF-8"

2.参数在请求实体中,也就是POST方式,这个时候你可以直接通过request.setCharacterEncoding("UTF-8");的方式设置,当然你可以运用一个过滤器来统一解决。

 

知道了原因,再去解决乱码一般就不会有什么问题了。

至于有些提出使用前台encodeURI(encodeURI(str))方式去做的,后台手动解码,其实还是由于两端编码和解码不一致造成的,完全不需要这么使用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值