久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

深度揭秘亂碼問題背后的原因及解決方式

 天地因心 2017-01-11

做Web開發(fā)的IT人,,如果工作中沒遇到過幾次亂碼的問題,,估計都不好意思說自己是開發(fā)工程師。 :)


而亂碼問題也是各種各樣,,有保存到數(shù)據(jù)庫中是亂碼的,,有在服務端接收到參數(shù)是亂碼的,有在后臺返回到客戶端時候出現(xiàn)亂碼的……


這形形色色的亂碼問題,,如果處理起來不得要領,,著實會讓開發(fā)人員費不少工夫。

本文,,將從亂碼的產(chǎn)生原因,,應用服務器內(nèi)部對參數(shù)的處理各方面詳解原理及解決方案。


1


編碼


在開發(fā)中,,只要有IO的地方,,都會涉及到編碼。例如下面的代碼:

System.out.println( 'Hello 中國' );


你猜這個會輸出什么呢,?

這個其實是和你的文件編碼有很大關系的,,可能會輸出

Hello 中國


也有可能會輸出成下面這個樣子


Hello ???


你可以改動IDE中的文件編碼重復試幾次,。那為什么會產(chǎn)生這個原因呢?

我們來看這行代碼執(zhí)行過程中的調(diào)用棧:


我們看到,,簡單的一句輸出,,也是有編碼的

看看CharsetEncoder,,實現(xiàn)類真多啊

再比如我們都無比熟悉的equals方法,,先聲明常量STR如下:


之后,代碼中有如下的邏輯


你認為,,這個時候會有輸出嗎,?

答案是看情況


當我把Constant類以UTF-8為編碼保存后,,把包含if邏輯的代碼以GBK保存之后,,equals執(zhí)行時比較的兩個參數(shù)就變成了下面的樣子:


所以這一定是不會為true的。

這也是亂碼產(chǎn)生的原因,,


原因即解碼時采用的encoding與編碼時用的encoding不一致所造成的,。




2


應用服務器內(nèi)的亂碼




Web應用中,亂碼的成因和上述分析是一致的,。

我們向應用服務器發(fā)送一個這樣的請求:


http://localhost:8080/test/servlet?abc=你好

服務器用request.getParameter('abc')來獲取,,這個時候有亂碼問題嗎?

答案依然是It depends.


這次的看情況是要看哪些情況呢,?有以下這些。


  • Tomcat的版本

  • 是否單獨設置通道的編碼

  • 是否有使用統(tǒng)一的編碼Filter



Tomcat默認對于不同的通道(Connector),,都可以獨立設置相關的編碼屬性,,例如默認是下面這樣的配置:

Connector port='8080' protocol='HTTP/1.1'
connectionTimeout='20000'
redirectPort='8443' />

而我們可以增加自定義的編碼配置:

Connector port='8080' protocol='HTTP/1.1'
connectionTimeout='20000'
redirectPort='8443' URIEncoding='UTF-8'/>


紅色的URIEncoding即為添加的屬性,這個參數(shù)是和Tomcat的版本有關系的,。

在Tomcat8中,,其對應的官方文檔是這樣說明的:


This specifies the character encoding used to decode the URI bytes, after %xx decoding the URL. If not specified, UTF-8 will be used unless the org.apache.catalina.STRICT_SERVLET_COMPLIANCE system property is set to

true in which case ISO-8859-1 will be used.


也就是不設置

-Dorg.apache.catalina.STRICT_SERVLET_COMPLIANCE=true

那默認的編碼會采用UTF-8。

但是在Tomcat的8.0之前版本官方文檔里是這樣寫的說明:


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.


也就是不特殊指定,,默認將使用ISO-8859-1進行編碼,。


看Connector的構造方法中,也是明確按此進行配置的

public Connector(String protocol) {
setProtocol(protocol);
...
//注意下面的代碼
if (!Globals.STRICT_SERVLET_COMPLIANCE) {
URIEncoding = 'UTF-8';
URIEncodingLower = URIEncoding.toLowerCase(Locale.ENGLISH);
}
}

這個配置又是如何作用于參數(shù)解析的呢,?看下面


public void service(org.apache.coyote.Request req,
org.apache.coyote.Response res)
throws Exception {
// Set query string encoding
req.getParameters().setQueryStringEncoding
(connector.getURIEncoding()); //注意這里,,具體去設置的是Parameters類的queryStringEncoding,這個屬性會在后面解析URL中包含的參數(shù)時用到。}
public void setQueryStringEncoding( String s ) {
queryStringEncoding=s;}


而具體參數(shù)處理時,,傳進去的就是這個queryStringEncoding

processParameters( decodedQuery, queryStringEncoding );
這種情況,,在Tomcat8中就不需要再顯示的配置URIEncoding了,而之前的版本則需要配置,。有上面的代碼參照,,我們看到,,對于URL中傳入的參數(shù),除了設置URIEncoding這個配置之外,,是沒有辦法保證的,。因為其解析參數(shù)時使用的是queryStringEncoding這個參數(shù),因此只有才保證傳到Tomcat的參數(shù)編碼和解碼正確了,。


而如果配置了統(tǒng)一的編碼過濾器,,則過濾器內(nèi)設置request的編碼一定要在解析參數(shù)前,即調(diào)用getParameter前設置,,否則并不生效,。這是因為parameter只會解析一次,之后就放到一個List中直接根據(jù)key返回了,。


那是不是設置一個統(tǒng)一的編碼Filter,,一切就萬事大吉了呢?


答案還是看情況吧,?

恭喜,,你會搶答啦!



3


JSP亂碼問題


我們都知道在jsp中,,可以設置這樣一個jsp頭

<%@ page contentType='text/html;charset=iso-8859-1' language='java' %>

那這個時候如果你的頁面中要輸出一些返回的中文數(shù)據(jù),,這個時候,頁面妥妥的出現(xiàn)了亂碼,。原因自然是iso-859-1不支持中文有關,。注意這里charset不寫依然是按iso-8859-1為默認值。


這時,,你想到了Filter,。在Filter中你大膽的設置了

resp.setCharacterEncoding(encoding);

這個時候,頁面展示卻依然華麗的亂碼了,。擦,,這是啥原因?


那這個時候,,在jsp中顯示數(shù)據(jù)的時候,,依然還是會出現(xiàn)亂碼的,此時注意觀察下響應頭:


看下面的代碼,,由于response在輸出的時候,。會獲取設置的encoding
/**
* Return the writer associated with this Response.
*
* @exception IllegalStateException if getOutputStream has
* already been called for this response
* @exception IOException if an input/output error occurs
*/
@Override
public PrintWriter getWriter()
throws IOException {

if (usingOutputStream) {
throw new IllegalStateException
(sm.getString('coyoteResponse.getWriter.ise'));
}

if (ENFORCE_ENCODING_IN_GET_WRITER) {
/*
* If the response's character encoding has not been specified as
* described in getCharacterEncoding (i.e., the method
* just returns the default value ISO-8859-1),
* getWriter updates it to ISO-8859-1
* (with the effect that a subsequent call to getContentType() will
* include a charset=ISO-8859-1 component which will also be
* reflected in the Content-Type response header, thereby satisfying
* the Servlet spec requirement that containers must communicate the
* character encoding used for the servlet response's writer to the
* client).
*/
setCharacterEncoding(getCharacterEncoding());
}

usingWriter = true;
outputBuffer.checkConverter();
if (writer == null) {
writer = new CoyoteWriter(outputBuffer);
}
return writer;
}

而這個encoding是什么設置的呢?
public void setContentType(String type) {

if (isCommitted()) {
return;
}

if (SecurityUtil.isPackageProtectionEnabled()){
AccessController.doPrivileged(new SetContentTypePrivilegedAction(type));
} else {
response.setContentType(type); //這里在設置contentType,由于配置中同時包含charset
}
}

String[] m = MEDIA_TYPE_CACHE.parse(type); //這個是在解析contentType參數(shù)
if (m == null) {
// Invalid - Assume no charset and just pass through whatever
// the user provided.
coyoteResponse.setContentTypeNoCharset(type);
return;
}

coyoteResponse.setContentTypeNoCharset(m[0]);

if (m[1] != null) {
// Ignore charset if getWriter() has already been called
if (!usingWriter) {
coyoteResponse.setCharacterEncoding(m[1]); //這里就用解析出來的參數(shù)設置,。
isCharacterEncodingSet = true;
}
}

而我們一般為了處理這種亂碼問題統(tǒng)一寫的filter,,在請求處理前就先把request和response的encoding都設置好。
而這里默認提供的charset為ISO-8859-1,就出了亂碼問題了,。另外一個在處理JSP時容易出的問題,,就是contentType中指定的charset和filter中已經(jīng)設置的encoding,,兩者不一致,比如你的jsp中忘記改了,,使用的是默認的ISO-8859-1.此時,,先通過filter設置的encoding會先于contentType的設置執(zhí)行,因此,,依然會出現(xiàn)亂碼問題,。

4

總結


在本文中,深入分析了亂碼背后產(chǎn)生的原因:編碼和解碼時采用的encoding不一致,。而解決問題的最樸素的道理就是保持多種數(shù)據(jù)來源編碼的一致性,,無論是數(shù)據(jù)庫的,文件的,,還是輸入輸出的,,都采用一致的編碼,可以簡少很多問題,。另外,,許多文件中有一些默認編碼,開發(fā)中可能不太注意,,此處也是容易出現(xiàn)問題的地方,。


    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點,。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,,謹防詐騙,。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報,。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多