實(shí)際運(yùn)用 Tomcat 5.0.19,我們了解在不修改 Tomcat 原始碼的狀況下,使用者透過(guò) Form submit 的資料將一律以 ISO8859-1 處理,程式設(shè)計(jì)師必須自行將字串將轉(zhuǎn)換為 Big5(繁體中文) or GB2312/GBK(簡(jiǎn)體中文),我們?cè)趹?yīng)用程式中,對(duì)所有的 request.getParameter("xx"); 作了 toBig5String() 的處理,理論上,所有的中文問(wèn)題應(yīng)該不會(huì)出現(xiàn)才對(duì),結(jié)果,還是發(fā)現(xiàn)某些狀況下,中文還是變成亂碼!

經(jīng)過(guò)分析整理,我們發(fā)現(xiàn)問(wèn)題出在 QueryString 的解析,以前在 Tomcat 4.x 時(shí)代,無(wú)論 SUBMIT 時(shí)採(cǎi)用 GET or POST,Tomcat server 對(duì) parameters 的處理都採(cǎi)用相同的編碼,但在 Tomcat 5.x 版,不知何故,卻將 QueryString 的解析獨(dú)立出來(lái),目前確認(rèn),F(xiàn)orm 的 Method 採(cǎi)用 GET 及直接將參數(shù)寫(xiě)在 URL 上的中文,上傳到 Tomcat 時(shí),無(wú)論如何轉(zhuǎn)碼,都會(huì)變成亂碼,那怕你事先作過(guò) URLEncode 也一樣。

網(wǎng)站上,有人針對(duì)這個(gè)問(wèn)題,建議將所有中文改採(cǎi)用 base64 編碼,到了 server 上,程式將自行土 base64 decode 回來(lái),確保中文不會(huì)發(fā)生問(wèn)題。這樣作法當(dāng)然可以解決這個(gè)問(wèn)題,但是所有網(wǎng)頁(yè)變成限定要採(cǎi)用 POST,且程式設(shè)計(jì)師要隨時(shí)分清楚,那個(gè)參數(shù)是採(cǎi)用 GET 上傳,那個(gè)參數(shù)是採(cǎi)用 POST 上傳,然後再針對(duì)不同的方式採(cǎi)用不同的解析,這樣的程式一點(diǎn)兒移植性都沒(méi)有,更別提跨平臺(tái)、跨國(guó)際語(yǔ)言了。

研究 Tomcat 的文件及原始碼,我們找到了問(wèn)題所在及解決的方法,只有按著以下的作法,才能使 Form submit 的資料完全按著 ISO8859-1 的編碼,當(dāng)然,若是全照著 Tomcat 的文件說(shuō)明去作,肯定還是不行,你還是得加上這個(gè)參數(shù)到 server.xml 中才行。

解決方案

請(qǐng)先研究 $TOMCAT_HOME/webapps/tomcat-docs/config/http.html 這個(gè)說(shuō)明檔,擷錄重點(diǎn)如下:
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.

上述二個(gè) Tomcat 參數(shù),是設(shè)定在 server.xml 中的 http <Connector /> 區(qū)塊,要解決 QueryString 中文變成亂碼的問(wèn)題,你必須至少設(shè)定這二個(gè)參數(shù)其中之一。
URIEncoding 請(qǐng)?jiān)O(shè)定為 URIEncoding="ISO-8859-1" 指定為 "ISO-8859-1" 編碼,讓 QueryString 的字元編碼與 post body 相同。
useBodyEncodingForURI 這是用來(lái)相容 Tomcat 4.x 版的,設(shè)定的值是 "true" or "false",意思是指 "要不要讓 QueryString 與 POST BODY 採(cǎi)用相同的字元編碼 ?",若是設(shè)成 true,那也可達(dá)到 "ISO-8859-1" 編碼的需求。
建議,採(cǎi)用 URIEncoding 的設(shè)定,畢竟 useBodyEncodingForURI 的作法是為了相容 Tomcat 4.X。不過(guò)若照原文的說(shuō)明,理論上這二個(gè)參數(shù)都不設(shè),Tomcat 也該採(cǎi)用 "ISO-8859-1" 的編碼,那為什麼還是會(huì)有問(wèn)題呢 ? 我們由 Tomcat Source Code 來(lái)看就清楚了。
// 這一段碼是 Tomcat 用來(lái)解 QueryString 的程式,
            // 在 org.apache.tomcat.util.http.Parameters 這個(gè) 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;
            }

請(qǐng)?zhí)貏e注意紅色區(qū)塊,當(dāng) Tomcat 發(fā)現(xiàn) QueryString 並沒(méi)有設(shè)定 encode 時(shí),並非像文件中所說(shuō)預(yù)設(shè)採(cǎi)用 ISO-8859-1 的編碼,而是用一段 fast conversion 來(lái)處理,才會(huì)造成中文問(wèn)題,所以,還是必須在 Server.xml 中,加上 URLEncoding 的參數(shù)設(shè)定才行哦。

Connector 的設(shè)定範(fàn)例:
<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>