实际运用Tomcat 5.0.19,我们了解在不修改Tomcat原始码的状况下,使用者透过Form submit的资料将一律以ISO8859-1处理,程式设计师必须自行将字串将转换为Big5(繁体中文) or GB2312/GBK(简体中文),我们在应用程式中,对所有的request.getParameter("xx");作了toBig5String()的处理,理论上,所有的中文问题应该不会出现才对,结果,还是发现某些状况下,中文还是变成乱码!
经过分析整理,我们发现问题出在QueryString的解析,以前在Tomcat 4.x时代,无论SUBMIT时采用GET or POST,Tomcat server对parameters的处理都采用相同的编码,但在Tomcat 5.x版,不知何故,却将QueryString的解析独立出来,目前确认,Form的Method采用GET及直接将参数写在URL上的中文,上传到Tomcat时,无论如何转码,都会变成乱码,那怕你事先作过URLEncode也一样。
网站上,有人针对这个问题,建议将所有中文改采用base64编码,到了server上,程式将自行土base64 decode回来,确保中文不会发生问题。这样作法当然可以解决这个问题,但是所有网页变成限定要采用POST,且程式设计师要随时分清楚,那个参数是采用GET上传,那个参数是采用POST上传,然后再针对不同的方式采用不同的解析,这样的程式一点儿移植性都没有,更别提跨平台、跨国际语言了。
研究Tomcat的文件及原始码,我们找到了问题所在及解决的方法,只有按着以下的作法,才能使Form submit的资料完全按着ISO8859-1的编码,当然,若是全照着Tomcat的文件说明去作,肯定还是不行,你还是得加上这个参数到server.xml中才行。
解决方案
请先研究$TOMCAT_HOME/webapps/tomcat-docs/config/http.html这个说明档,撷录重点如下:
URIEncoding:This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, ISO-8859-1 will be used.
useBodyEncodingForURI:This specifies if the encoding specified in contentType should be used for URI query parameters, instead of using the URIEncoding. This setting is present for compatibility with Tomcat 4.1.x, where the encoding specified in the contentType, or explicitely set using Request. setCharacterEncoding method was also used for the parameters from the URL. The default value is false.
上述二个Tomcat参数,是设定在server.xml中的http <Connector />区块,要解决QueryString中文变成乱码的问题,你必须至少设定这二个参数其中之一。
URIEncoding请设定为URIEncoding="ISO-8859-1"指定为"ISO-8859-1"编码,让QueryString的字元编码与post body相同。
useBodyEncodingForURI这是用来相容Tomcat 4.x版的,设定的值是"true" or "false",意思是指"要不要让QueryString与POST BODY采用相同的字元编码?",若是设成true ,那也可达到"ISO-8859-1"编码的需求。
建议,采用URIEncoding的设定,毕竟useBodyEncodingForURI的作法是为了相容Tomcat 4.X。不过若照原文的说明,理论上这二个参数都不设,Tomcat也该采用"ISO-8859-1"的编码,那为什么还是会有问题呢?我们由Tomcat Source Code来看就清楚了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
// 这一段代码是 Tomcat 用来解 QueryString 的程式,
// 在 org.apache.tomcat.util.http.Parameters 這個 class 裡。
private String urlDecode(ByteChunk bc, String enc)
throws IOException {
if( urlDec==null ) {
urlDec=new UDecoder();
}
urlDec.convert(bc);
String result = null;
if (enc != null) {
bc.setEncoding(enc);
result = bc.toString();
}
else {
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;
} |
请特别注意红色区块,当Tomcat发现QueryString并没有设定encode时,并非像文件中所说预设采用ISO-8859-1的编码,而是用一段fast conversion来处理,才会造成中文问题,所以,还是必须在Server.xml中,加上URLEncoding的参数设定才行哦。
Connector的设定范例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
|
<Connector
debug="0"
acceptCount="100"
connectionTimeout="20000"
disableUploadTimeout="true"
port="80"
redirectPort="8443"
enableLookups="false"
minSpareThreads="25"
maxSpareThreads="75"
maxThreads="150"
maxPostSize="0"
URIEncoding="ISO-8859-1"
>
</Connector> |