从Tomcat源码分析中文乱码问题

tomcat中的乱码基本上有两种

第一类是*.jsp文件中的中文无法正确显示。
第二类是 request 中的 parameter 取出来是乱码


第 一类:每个*.jsp文件最终会被编译成一个servlet, 即一个java文件,放到tomcat的work目录下,在访问*.jsp文件时,实际上是运行这个servlet类。 出现乱码的原因是:在将jsp编译成java文件时,采用的默认字符集是iso8859_1, 其中的中文无法正常识别,被编译成iso-8859-1格式,与中文的GBK或GB2312不兼容。 这个工作是由 org.apache.jasper 包完成的。
在每个jsp文件的开头加入 <%@ page contentType="text/html;charset=GBK"%>即可以告诉jasper,在编译时采用GBK格式。
只要去下面的方法中把"ISO-8859-1" 都改为"GBK" 即可完成和上面相同的功能。
void org.apache.jasper.compiler.ParserController.determineSyntaxAndEncoding(String absFileName, JarFile jarFile, String jspConfigPageEnc) throws JasperException, IOException


第二类:每个request对象实际上都是被封装为一个org.apache.coyote.tomcat5.CoyoteRequestFacade类

在调用 request.getParameter时, tomcat 会进行如下的处理。

1. 将请求传给下面的 CoyoteRequest 实例
String org.apache.coyote.tomcat5.CoyoteRequestFacade.getParameter(String name){
return request.getParameter(name);
}

2. parameter 只有在需要时才被parse, 如果不掉用request.getParameter 或者 request.getParameterValues 之类方法就不会进行parameter 的处理
String org.apache.coyote.tomcat5.CoyoteRequest.getParameter(String name)
if (!requestParametersParsed)
parseRequestParameters();
}

3.设置相应的编码。 调用org.apache.tomcat.util.http.Parameters类进行 parameter parsing
void org.apache.coyote.tomcat5.CoyoteRequest.parseRequestParameters() {

requestParametersParsed = true;

Parameters parameters = coyoteRequest.getParameters(); && coyoteRequest 是org.apache.coyote.Request 对象的一个实例

String enc = coyoteRequest.getCharacterEncoding(); &&此处取到的值是 request.setCharacterEncoding 中设置的值, 如果没有设置,取出null
if (enc != null) {
parameters.setEncoding(enc);
if (useBodyEncodingForURI) { && useBodyEncodingForURI 一般是false,所以 parameter的queryStringEncoding 是默认值null
parameters.setQueryStringEncoding(enc);
}
} else { &&&这里说明为什么如果不调用 request.setCharacterEncoding, 会采用默认 sio-8859-1编码
parameters.setEncoding
(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING); &&这里默认值是ISO-8859-1
if (useBodyEncodingForURI) {
parameters.setQueryStringEncoding && useBodyEncodingForURI 一般是false,所以 parameter的queryStringEncoding 是默认值null
(org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
}
}

parameters.handleQueryParameters(); && 此处的 queryParameter 是指类似 "test.jsp?para1=aaa¶2=bbb" 中的 "para1=aaa&2=bbb"

&&以上是处理 http-get请求的代码,下面是处理http-post请求的代码,和上面的类似。省略。

}

4.对queryString 进行相应处理后继续向下传递
void org.apache.tomcat.util.http.Parameters.handleQueryParameters(){
processParameters(bc.getBytes(), bc.getOffset(), bc.getLength(),queryStringEncoding);
&& queryStringEncoding是null, 见3中的注释
}

5.将decode之后的parameter 和值保存起来
void org.apache.tomcat.util.http.Parameters.processParameters(byte[] bytes, int start, int len, String enc){
addParam(urlDecode(tmpName, enc), urlDecode(tmpValue, enc)); &&enc 一般情况下是null
&&tmpName 是parameter名字 tmpValue是parameter 的值
}

6.此处是关键, parameter的 name 和 prameter的 value在这个方法中被decode.
String org.apache.tomcat.util.http.Parameters.urlDecode(ByteChunk bc, String enc) throws IOException{
String result = null;
$$$$$$$$$$$$$$$$$$$$$$$!!!!!!!! 在这里加一行 enc="GBK", 所有的问题都可以解决了
if (enc != null) { && 此段代码一般不会执行,enc 是null, 见3,4,5中的注释
bc.setEncoding(enc);
result = bc.toString();
} else { &&此处是转换为iso_8859_1, 这是默认值。
CharChunk cc = tmpNameC;
cc.allocate(bc.getLength(), -1);
// Default encoding: fast conversion
byte[] bbuf = bc.getBuffer();
char[] cbuf = cc.getBuffer();
int start = bc.getStart();
for (int i = 0; i < bc.getLength(); i++) {
cbuf[i] = (char) (bbuf[i + start] & 0xff);
}
cc.setChars(cbuf, 0, bc.getLength());
result = cc.toString();
cc.recycle();
}
return result;
}



只需在6中的方法里加一行 enc="GBK", 从request中取出的中文就不会有编码问题了。
而且,即使在jsp页面中写如下代码可以正常运行




<form method="get" action="test.jsp">

<input type="text" name="参数">

</form>

<% System.out.println(request.getParameter("参数")); %>


当然,前提是jsp中的中文必须被编译成合法的编码。即按1中所说的方法进行处理

3.如何更改并替换类。

可以从相应的jar包中找到相应的类,反编译后更改,再编译成新的类。

可以去apache 网站下载相应的源代码,更改然后编译成新的类。

有两种方法可以替换旧的类为新改过的类。

一是直接找到相应的jar文件,把新编译的类覆盖进去。可以用winrar打开jar文件,然后直接把新的类拖进去就可以了。

二是在相应的目录下面建对应的目录结构,把对应的类放在下面。因为classloader在loading 新的类时是先去文件目录找类,然后在去jar文件中找,所以目录下面的类优先于jar中的类。
比 如,更改了 org.apache.jasper.compiler.ParserController 类之后,可以去 %tomcat-home%commonlibjasper-compiler.jar 中把 原有的 ParserController.class直接覆盖。
或者也可以在 %tomcat-home%commonclasses 中建一个 orgapachejaspercompiler 目录,把改好的ParserController.class 放进去。

如 果要更改org.apache.tomcat.util.http.Parameters 类,可以覆盖 %tomcat-home%serverlibtomcat-util.jar 中的 Parameters.class, 或者建立 %tomcat-home%serverclassesorgapachetomcatutilhttp 目录,把新的 Parameters.class 放在下面。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值