Web開發(fā)中的中文亂碼問(wèn)題

主要內(nèi)容
1. 字符編碼理論簡(jiǎn)述
    1.1 ASCII
    1.2 ISO8859-1
    1.3 Unicode
    1.4 GBK
    
2. 可能發(fā)生的中文亂碼
    2.1 中文變問(wèn)號(hào)玫镐,如:???
    2.2 中文變奇怪字符一罩,如:?? ?¥? 或者 ??o?
    2.3 中文變“復(fù)雜中文”,如:浣犲ソ
    2.4 中文變成一堆黑色菱形+問(wèn)號(hào),如:?????

3. Web開發(fā)中涉及到的中文編解碼
    3.1 URL中出現(xiàn)的中文
    3.2 Form表單中出現(xiàn)的中文
    3.3 JSP中涉及的編碼
    3.4 文件的上傳和下載中涉及到的中文亂碼
4. 總結(jié)

1. 字符編碼理論簡(jiǎn)述

本文主要是圍繞Web開發(fā)中涉及到的中文編碼這一常見問(wèn)題展開顷帖,包括了對(duì)字符編碼基礎(chǔ)理論的簡(jiǎn)述以及常見幾種編碼標(biāo)準(zhǔn)的介紹逆航。其中包括:ASCII鼎文、ISO8859-1、Unicode因俐、GBK拇惋。下面先對(duì)這些字符編碼集進(jìn)行簡(jiǎn)單的介紹。

1.1 ASCII

ASCII也就是美國(guó)信息交換標(biāo)準(zhǔn)碼抹剩,采用單字節(jié)編碼方案撑帖,但是編碼只用了后七位字節(jié),表示范圍0-127共128個(gè)字符澳眷。ASCII碼相對(duì)于其它編碼也是最早出現(xiàn)的磷仰。從上世紀(jì)60年代提出開始,到1986年最終定型境蔼。

為什么選擇7位編碼?ASCII在最初設(shè)計(jì)的時(shí)候需要至少能表示64個(gè)碼元:包括26個(gè)字母+10個(gè)數(shù)字+圖形標(biāo)示+控制字符灶平,如果用6bit編碼,可擴(kuò)展部分沒(méi)有了箍土,所以至少需要7bit逢享。那么8bit呢?最終也被標(biāo)準(zhǔn)委員會(huì)否定吴藻,原因很簡(jiǎn)單:滿足編碼需求的前提下瞒爬,最小化傳輸開銷。

1.2 ISO8859-1

ISO-8859-1也被稱為L(zhǎng)atin1,使用單字節(jié)8bit編碼侧但,可以表示256個(gè)西歐字符矢空。其隸屬于ISO8859標(biāo)準(zhǔn)的一部分,還有ISO8859-2禀横、ISO8859-3等等屁药。每一種編碼都對(duì)應(yīng)一個(gè)地區(qū)的字符集。比如:ISO8859-1表示西歐字符柏锄,ISO-8859-16表示中歐字符集酿箭,等等。

1.3 Unicode

不管是ASCII還是ISO8859-1趾娃,其編碼范圍都是有局限的缭嫡。而Unicode標(biāo)準(zhǔn)的目標(biāo)就是消除傳統(tǒng)編碼的局限性

這里的局限性一方面指編碼范圍的局限性:比如ASCII只能表示128個(gè)字符抬闷。還有編碼兼容性方面的局限性:比如ISO8859代表的一系列編碼字符集雖然可以表示大部分國(guó)家地區(qū)的字符妇蛀,但是彼此的兼容性做的不好。Unicode的目標(biāo)就如同其名稱的含義一樣:“實(shí)現(xiàn)字符編碼統(tǒng)一”

Unicode標(biāo)準(zhǔn)的實(shí)現(xiàn)方案有如下三種:UTF-8笤成、UTF-16和UTF-32**.

UTF-8是變長(zhǎng)編碼讥耗,使用1到4個(gè)字節(jié)。UTF-8在設(shè)計(jì)時(shí)考慮到向前兼容疹启,所以其前128個(gè)字符和ASCII完全一樣,也就是說(shuō)蔼卡,所有ASCII同時(shí)也都符合UTF-8編碼格式喊崖。其格式如下:

0xxxxxxx
110xxxxx    10xxxxxx
1110xxxx    10xxxxxx    10xxxxxx
11110xxx    10xxxxxx    10xxxxxx    10xxxxxx

字節(jié)首部為0的話,也就是前面說(shuō)的ASCII了雇逞。此外荤懂,字節(jié)首部連續(xù)1的個(gè)數(shù)就代表了該字符編碼后所占的字節(jié)數(shù)。目前全世界的網(wǎng)頁(yè)編碼絕大多數(shù)使用的就是UTF-8塘砸,占比接近90%节仿。

UTF-16也是變長(zhǎng)編碼,但其最初是固定16-bit寬度的定長(zhǎng)編碼掉蔬,主要因?yàn)閁nicode涵蓋的字符太多了廊宪。兩字節(jié)更本不夠用!

UTF-32是32-bit定長(zhǎng)編碼女轿,優(yōu)點(diǎn):定長(zhǎng)編碼在處理效率上相對(duì)于變長(zhǎng)編碼要高箭启,此外,可通過(guò)索引訪問(wèn)任意字符是其另一大優(yōu)勢(shì)蛉迹;缺點(diǎn)也很明顯:32bit太浪費(fèi)了傅寡!存儲(chǔ)效率太低!

big-endian和little-endian?在多字節(jié)編碼標(biāo)準(zhǔn)中可能會(huì)遇到這樣的問(wèn)題:假如一個(gè)字符用兩個(gè)字節(jié)表示荐操,那么當(dāng)讀取這個(gè)字符的時(shí)候芜抒,哪個(gè)字節(jié)表示高有效位?哪個(gè)表示低有效位呢托启?這就涉及到字節(jié)的存儲(chǔ)順序問(wèn)題宅倒。在Unicode中UTF-16和UTF-32都會(huì)面臨這個(gè)問(wèn)題。通常用BOM(Byte Order Mark)來(lái)進(jìn)行區(qū)分驾中。BOM用一個(gè)"U+FEFF"來(lái)表示唉堪,這個(gè)值在
Unicode中是沒(méi)有對(duì)應(yīng)字符的。不僅可以用其來(lái)指定字節(jié)順序肩民,還可以表示字節(jié)流的編碼方式唠亚。

System.out.println("len1:" + "a".getBytes("UTF16").length);
System.out.println("len2:" + "aa".getBytes("UTF16").length);

輸出結(jié)果:

len1:4

len2:6

為什么是4和6,不應(yīng)該是2和4嗎3痔怠灶搜?。輸出編碼后的字節(jié)序列可以發(fā)現(xiàn)工窍,起始的兩個(gè)字節(jié)都是:"fe ff"割卖。

Java的char類型用什么編碼格式?Java語(yǔ)言規(guī)范規(guī)定了Java的char類型使用的是UTF-16患雏。這就是為什么Java的char占用兩個(gè)字節(jié)的原因鹏溯。此外,Java標(biāo)準(zhǔn)庫(kù)實(shí)現(xiàn)的對(duì)char與String的序列化規(guī)定使用UTF-8淹仑。Java的Class文件中的字符串常量與符號(hào)名字也都規(guī)定用UTF-8編碼丙挽。這大概是當(dāng)時(shí)設(shè)計(jì)者為了平衡運(yùn)行時(shí)的時(shí)間效率(采用定長(zhǎng)編碼的UTF-16,當(dāng)然匀借,在設(shè)計(jì)java的時(shí)候UTF-16還是定長(zhǎng)的)與外部存儲(chǔ)的空間效率(采用變長(zhǎng)的UTF-8編碼)而做的取舍颜阐。

1.4 GBK

GBK是用于對(duì)簡(jiǎn)體中文進(jìn)行編碼。每個(gè)字符用兩字節(jié)表示吓肋,同時(shí)兼容GB2312標(biāo)準(zhǔn)凳怨。

2. 可能發(fā)生的中文亂碼

這一小節(jié)介紹軟件開發(fā)中常見的中文編碼亂碼問(wèn)題,在下面示例中:對(duì)于給定的一個(gè)包含中文的字符串"你好Java"是鬼,看一下都會(huì)出現(xiàn)哪些亂碼問(wèn)題肤舞。

2.1 中文變問(wèn)號(hào),如:?????

"你好Java"  ------>  "??Java"

這種情況一般是由于中文字符經(jīng)ISO8859-1編碼造成的均蜜。下面是編碼的具體過(guò)程:

原字符串:"你好Java"

J a v a
4f60 597d 4a 61 76 61

經(jīng)ISO8859-1編碼后:

J a v a
3f 3f 4a 61 76 61

編碼后字符串:"??Java"

String str = "你好Java";
System.out.println(byteToHexString(str.getBytes(CHARSET_ISO88591)));
System.out.println(new String(str.getBytes(CHARSET_ISO88591)));
輸出:
3f 3f 4a 61 76 61
??Java

我們知道ISO8859-1是單字節(jié)編碼萨赁,而對(duì)于漢字已經(jīng)超出ISO8859-1的編碼范圍,會(huì)被轉(zhuǎn)化為"3f"兆龙,我們查表可知杖爽,"3f"對(duì)應(yīng)的字符正是"?"敲董。

中文變問(wèn)號(hào)的亂碼情況是非常常見的,大部分開源軟件的默認(rèn)編碼設(shè)置成了ISO8859-1慰安,這點(diǎn)需要格外注意腋寨。

2.2 中文變奇怪字符,如:?? ?¥? 或者 ??o?

"你好Java"  ------>  "?? ?¥?Java"

原字符串:"你好Java"

J a v a
4f60 597d 4a 61 76 61

經(jīng)UTF-8編碼后化焕,一個(gè)中文用三個(gè)字節(jié)表示:

你 | 好 | J| a| v| a
---|---|---|---|---|---|---|---
e4 bd a0 | e5 a5 bd | 4a| 61| 76| 61

亂碼原因:UTF8編碼或GBK編碼萄窜,再由ISO8859-1解碼。對(duì)照ISO8859-1編碼表后發(fā)現(xiàn):e4 bd a0分別對(duì)應(yīng)三個(gè)字符:"?? ",e5 a5 bd分別對(duì)應(yīng)三個(gè)字符"?¥?",

2.3 中文變“復(fù)雜中文”如:浣犲ソ

下面依然是"你好Java"經(jīng)過(guò)UTF-8編碼后對(duì)應(yīng)的字節(jié)序列:

你 | 好 | J| a| v| a
---|---|---|---|---|---|---|---
e4 bd a0 | e5 a5 bd | 4a| 61| 76| 61

在GBK表中查找:e4 bd對(duì)應(yīng)字符:"浣",a0 e5對(duì)應(yīng)字符:"犲",a5 bd對(duì)應(yīng)字符:"ソ"

同理撒桨,如果GBK編碼的中文用UTF-8來(lái)解碼的話查刻,同樣會(huì)出現(xiàn)亂碼問(wèn)題。

2.4 中文變成一堆黑色菱形+問(wèn)號(hào)凤类,如:?????

首先問(wèn)號(hào)+黑色菱形的字符是Unicode中的"REPLACEMENT CHARACTER",該字符的主要作用是用來(lái)表示不識(shí)別的字符穗泵。
所以產(chǎn)生亂碼的原因可能有很多,下面通過(guò)原字符串:"你好Java"谜疤,重現(xiàn)一種亂碼方式:

原字符串:String str = "你好Java"

你 | 好 | J| a| v| a
---|---|---|---|---|---
4f60 | 597d | 4a| 61| 76| 61

UTF-16編碼后

fe ff 4f 60 59 7d 0 4a 0 61 0 76 0 61

其中"fe ff"就是字節(jié)流起始的BOM標(biāo)識(shí)符佃延。"fe ff"在Unicode標(biāo)準(zhǔn)中屬于"noncharacters",只用于內(nèi)部使用。所以夷磕,
在輸出該字節(jié)序列的時(shí)候履肃,沒(méi)有該碼元對(duì)應(yīng)的字符,對(duì)于不識(shí)別字符坐桩,就會(huì)用??替代尺棋。

3. Web開發(fā)中涉及到的中文編解碼

Web中的數(shù)據(jù)大多通過(guò)http協(xié)議進(jìn)行傳輸,所涉及到的一些編解碼問(wèn)題都圍繞著http協(xié)議绵跷。下面以Tomcat作為Web服務(wù)器膘螟,
探討下一個(gè)完整的請(qǐng)求響應(yīng)流程中哪些地方會(huì)涉及到中文的編解碼。

3.1 url編解碼

web環(huán)境中的中文亂碼問(wèn)題抖坪,實(shí)驗(yàn)如下:

jsp中的form表單:
<body>
    <form name="form" method="post" action="manager/codec/你好">
        <table>
            <tr>
                <td>用戶名: <input type="text" name="name" id="name" />
                </td>
                <td>地址 <input type="text" name="address" id="address" />
                </td>
                <th><input type="submit" name="submit" value="保存" /></th>
            </tr>
        </table>
    </form>
</body>

后端使用SpringMVC的Controller:

@Controller()
@RequestMapping("/manager")
public class ManagerController {

    @RequestMapping("/test/{param}")
    @ResponseBody
    public String test(@PathVariable String param, HttpServletRequest request){
        String name = request.getParameter("name");
        System.out.println("name:" + name + ",param:" + param);
        return "test";
    }
}

表單中填入內(nèi)容:
用戶名:你好 Java
地址:123
提交請(qǐng)求,firebug中的顯示的url如下:

http://localhost:8080/fdyuntu-ssm/manager/codec/%E4%BD%A0%E5%A5%BD

查閱編碼可以闷叉,firefox對(duì)url中出現(xiàn)的中文使用了UTF-8的編碼方式擦俐。之所以u(píng)rl中出現(xiàn)%,這是因?yàn)楦鶕?jù)URL編碼規(guī)范握侧,瀏覽器會(huì)將非ASCII字符編成16進(jìn)制后蚯瞧,每個(gè)字節(jié)前需要加%。

后端控制臺(tái)輸出:

name:?? ?¥? Java,param:?? ?¥?

可見無(wú)論是url中的中文信息或是post表單中的中文都出現(xiàn)了亂碼現(xiàn)象品擎,從前一節(jié)中關(guān)于亂碼情況的分析來(lái)看埋合,這里應(yīng)該是中文字符經(jīng)過(guò)瀏覽器UTF-8編碼后,Server端用ISO8859-1進(jìn)行解碼所致萄传。下面逐個(gè)分析url和post表單如何進(jìn)行編解碼的甚颂。

在tomcat中url的byte -> char的轉(zhuǎn)換是在org.apache.catalina.connector.CoyoteAdapter類的convertURI(MessageBytes uri, Request request)方法中執(zhí)行的,源碼如下:

    protected void convertURI(MessageBytes uri, Request request)throws Exception {

        ByteChunk bc = uri.getByteChunk();
        int length = bc.getLength();
        CharChunk cc = uri.getCharChunk();
        cc.allocate(length, -1);
    
//這里獲取的connector的URIEncoding屬性,即server.xml文件中connector元素的URIEncoding屬性
        String enc = connector.getURIEncoding();
        if (enc != null) {
            B2CConverter conv = request.getURIConverter();
            try {
                if (conv == null) {
                    conv = new B2CConverter(enc, true);
                    request.setURIConverter(conv);
                } else {
                    conv.recycle();
                }
            } catch (IOException e) {
                log.error("Invalid URI encoding; using HTTP default");
                connector.setURIEncoding(null);
            }
            if (conv != null) {
                try {
                    conv.convert(bc, cc, true);
                    uri.setChars(cc.getBuffer(), cc.getStart(), cc.getLength());
                    return;
                } catch (IOException ioe) {
                    request.getResponse().sendError(
                            HttpServletResponse.SC_BAD_REQUEST);
                }
            }
        }

        // 如果沒(méi)有配置URIEncoding振诬,則在ByteChunk中默認(rèn)使用ISO8859-1蹭睡。
        byte[] bbuf = bc.getBuffer();
        char[] cbuf = cc.getBuffer();
        int start = bc.getStart();
        for (int i = 0; i < length; i++) {
            cbuf[i] = (char) (bbuf[i + start] & 0xff);
        }
        uri.setChars(cbuf, 0, length);
    }

在org.apache.tomcat.util.buf.ByteChunk中可以看到默認(rèn)編碼的定義:

public final class ByteChunk implements Cloneable, Serializable {

    //。赶么。肩豁。
    
    public static final Charset DEFAULT_CHARSET = B2CConverter.ISO_8859_1;
    
    //。辫呻。清钥。
}

所以對(duì)于請(qǐng)求url中的中文,我們按UTF-8進(jìn)行編碼放闺,在服務(wù)端卻按ISO8859-1進(jìn)行解碼祟昭,所以出現(xiàn)亂碼現(xiàn)象。我們可以再Tomcat的server.xml中指定url的編解碼格式雄人,如下:

<Connector  URIEncoding="UTF-8" 从橘。。础钠。>

此時(shí)重復(fù)上面實(shí)驗(yàn)恰力,后端控制臺(tái)輸出:name:?? ?¥? Java,param:你好

雖然url中的參數(shù)可以正常顯示了,但是form表單中的參數(shù)name依然亂碼,下面進(jìn)一步分析庆猫。

3.2 form表單元素的編解碼

name參數(shù)的編碼依然是亂碼的凸丸,為啥?首先定位form表單中參數(shù)是在哪里進(jìn)行解碼的香府。Form表單中的字符解碼時(shí)機(jī)是發(fā)生在第一次調(diào)用request.getParameter時(shí),可以通過(guò)request.setCharacterEncoding設(shè)置码倦。需要注意的是setCharacterEncoding必須在getParameter之前調(diào)用企孩!否則,setCharacterEncoding不會(huì)起作用袁稽。

Tomcat中HttpServletRequest接口的實(shí)現(xiàn)類是org.apache.catalina.connector.Request勿璃。下面是Request類中g(shù)etParameter源碼:

    @Override
    public String getParameter(String name) {
        //判斷參數(shù)是否被解析過(guò)
        if (!parametersParsed) {
            parseParameters();//第一次參數(shù)解析
        }
        
        return coyoteRequest.getParameters().getParameter(name);
    }

//下面是parseParameters部分源碼

   protected void parseParameters() {
        
        //設(shè)為true,表示參數(shù)已解析過(guò)
        parametersParsed = true;
        //Parameters對(duì)象封裝了form表單參數(shù)
        Parameters parameters = coyoteRequest.getParameters();
        
        boolean success = false;
        try {
            // Set this every time in case limit has been changed via JMX
            parameters.setLimit(getConnector().getMaxParameterCount());
        
            //獲取字符編碼格式
            String enc = getCharacterEncoding();

            boolean useBodyEncodingForURI = connector.getUseBodyEncodingForURI();
            if (enc != null) {
            //getCharacterEncoding不為null推汽,則對(duì)應(yīng)設(shè)置編碼方式
                parameters.setEncoding(enc);
                if (useBodyEncodingForURI) {
                    parameters.setQueryStringEncoding(enc);
                }
            } else {
                //如果enc為null补疑,則編碼方式設(shè)置為DEFAULT_CHARACTER_ENCODING,也就是ISO8859-1
                parameters.setEncoding
                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
                if (useBodyEncodingForURI) {
                    parameters.setQueryStringEncoding
                    (org.apache.coyote.Constants.DEFAULT_CHARACTER_ENCODING);
                }
            }

            parameters.handleQueryParameters();
            
            歹撒。莲组。。
        }
    }

從以上源碼中可以看出為什么需要在第一次調(diào)用getParameter之前設(shè)置CharacterEncoding暖夭。因?yàn)榈谝淮螆?zhí)行parseParameters時(shí)锹杈,會(huì)把parametersParsed變量設(shè)為true撵孤。所以parseParameters只會(huì)在第一次getParameter時(shí)調(diào)用。有時(shí)會(huì)出現(xiàn)這么一種怪像:通過(guò)request.getCharacterEncoding()得到的是我們認(rèn)為正確的編碼字符集嬉橙,但是request.getParameter得到的依然是亂碼早直。此時(shí)就需要考慮下我們調(diào)用setCharacterEncoding之前是否已經(jīng)調(diào)用過(guò)getParameter方法了。

經(jīng)過(guò)上面的分析后市框,對(duì)于form表單參數(shù)亂碼問(wèn)題就很好解決了霞扬,在第一次調(diào)用request.getParameter方法前,通過(guò)request.setCharacterEncoding("Expected_Encoding");設(shè)置即可枫振。這一步可以用Servlet標(biāo)準(zhǔn)中的Filter實(shí)現(xiàn)喻圃,不過(guò),常用的MVC框架中已經(jīng)有現(xiàn)成的Filter實(shí)現(xiàn)了粪滤,比如SpringMVC中的org.springframework.web.filter.CharacterEncodingFilter,如下:

    @Override
    protected void doFilterInternal(
            HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
            throws ServletException, IOException {

        if (this.encoding != null && (this.forceEncoding || request.getCharacterEncoding() == null)) {
            request.setCharacterEncoding(this.encoding);//設(shè)置指定的編碼
            if (this.forceEncoding) {
                response.setCharacterEncoding(this.encoding);
            }
        }
        filterChain.doFilter(request, response);
    }

3.3 JSP中涉及的編碼

jsp中可以通過(guò)page指令指定一些編碼參數(shù)斧拍,如下:

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
pageEncoding="UTF-8"在什么時(shí)候起作用?

在Servlet標(biāo)準(zhǔn)中杖小,jsp最終也會(huì)被編譯成一個(gè)servlet肆汹。index.jsp->index_jsp.java.pageEncoding="UTF-8"就是在這個(gè)解析過(guò)程中起作用的。

contentType="text/html; charset=UTF-8"的作用予权?

contentType是響應(yīng)頭中特定信息昂勉,主要的作用是告訴瀏覽器response中存放的主體對(duì)象類型和編碼,這樣瀏覽器就可以對(duì)指定類型進(jìn)行正確解碼扫腺,保證了數(shù)據(jù)在server和client端的一致性岗照。當(dāng)進(jìn)行Servlet編程的時(shí)候,可以手動(dòng)進(jìn)行設(shè)置笆环,如下:

response.setContentType("text/html; charset=UTF-8");

3.4 文件的上傳和下載中涉及到的中文亂碼

Web中的文件操作主要是上傳和下載攒至,這個(gè)過(guò)程也是依托于Http協(xié)議作為數(shù)據(jù)載體。所以躁劣,最終是否亂碼重點(diǎn)在于是否正確的設(shè)置http的request迫吐、response的header中的相關(guān)字段。如ContentType账忘、Content-Disposition的設(shè)定等志膀。如下:

response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-cache");
response.setDateHeader("Expires", 0);
response.setContentType("application/x-msdownload");
response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");

這里需要注意的是Content-Disposition的filename屬性值,如果fileName含有中文闪萄,那么要格外注意fileName字符串的編碼格式梧却。在rfc5987對(duì)于HTTP的Header中參數(shù)的編碼做出了明確的規(guī)定:

By default, message header field parameters in Hypertext Transfer Protocol (HTTP) messages cannot carry characters outside the ISO-8859-1 character set.

也就是說(shuō)默認(rèn)情況下奇颠,Http的Header中的參數(shù)只能用ISO-8859-1字符集中的字符败去,那么是否意味著Content-Disposition中的fileName字符串也要轉(zhuǎn)成ISO-8859-1了呢?答案是:NO烈拒!原因如下:Content-Disposition其實(shí)不屬于Http/1.1標(biāo)準(zhǔn)圆裕。這在RFC2616中有明確的說(shuō)明广鳍。只因?yàn)槠涫褂脧V泛,HTTP才對(duì)其支持吓妆。在rfc6266中也詳細(xì)介紹了Content-Disposition的filename參數(shù)含義和用法赊时。下面是對(duì)于下載包含中文名稱的文件時(shí)的解決方案。

解決方案

最簡(jiǎn)單就是直接用ISO8859-1對(duì)文件名進(jìn)行編碼行拢,大多數(shù)瀏覽器都支持祖秒。如下:

exportFileName.getBytes("UTF-8"),"ISO8859-1");//這里的UTF-8也可能是別的編碼,主要依據(jù)系統(tǒng)默認(rèn)的編碼來(lái)設(shè)定舟奠。

或通過(guò)其它編碼竭缝,如UTF-8。

response.addHeader("Content-Disposition",
                "attachment; filename*=UTF-8''" + URLEncoder.encode(exportFileName, "UTF8"));

4. 總結(jié)

編解碼問(wèn)題是多語(yǔ)言交互系統(tǒng)中必然要面對(duì)的問(wèn)題沼瘫,尤其對(duì)于中文環(huán)境中的開發(fā)者來(lái)說(shuō)抬纸,在入門階段或多或少都會(huì)遇到此類問(wèn)題。亂碼問(wèn)題本質(zhì)就是通信雙方使用的標(biāo)準(zhǔn)不一致耿戚。所以湿故,解決亂碼問(wèn)題的方法其實(shí)也很簡(jiǎn)單,統(tǒng)一下編解碼標(biāo)準(zhǔn)即可膜蛔。此外坛猪,深入理解各種編碼標(biāo)準(zhǔn)的原理和關(guān)系也非常重要,在以后遇到類似問(wèn)題的時(shí)候能夠更加準(zhǔn)確的判斷出造成亂碼的原因飞几。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末砚哆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子屑墨,更是在濱河造成了極大的恐慌躁锁,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,755評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件卵史,死亡現(xiàn)場(chǎng)離奇詭異战转,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)以躯,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門槐秧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人忧设,你說(shuō)我怎么就攤上這事刁标。” “怎么了址晕?”我有些...
    開封第一講書人閱讀 165,138評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵膀懈,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我谨垃,道長(zhǎng)启搂,這世上最難降的妖魔是什么硼控? 我笑而不...
    開封第一講書人閱讀 58,791評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮胳赌,結(jié)果婚禮上牢撼,老公的妹妹穿的比我還像新娘。我一直安慰自己疑苫,他們只是感情好熏版,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,794評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著捍掺,像睡著了一般纳决。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上乡小,一...
    開封第一講書人閱讀 51,631評(píng)論 1 305
  • 那天阔加,我揣著相機(jī)與錄音,去河邊找鬼满钟。 笑死胜榔,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的湃番。 我是一名探鬼主播夭织,決...
    沈念sama閱讀 40,362評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吠撮!你這毒婦竟也來(lái)了尊惰?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,264評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤泥兰,失蹤者是張志新(化名)和其女友劉穎弄屡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體鞋诗,經(jīng)...
    沈念sama閱讀 45,724評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡膀捷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了削彬。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片全庸。...
    茶點(diǎn)故事閱讀 40,040評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖融痛,靈堂內(nèi)的尸體忽然破棺而出壶笼,到底是詐尸還是另有隱情,我是刑警寧澤雁刷,帶...
    沈念sama閱讀 35,742評(píng)論 5 346
  • 正文 年R本政府宣布覆劈,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏墩崩。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,364評(píng)論 3 330
  • 文/蒙蒙 一侯勉、第九天 我趴在偏房一處隱蔽的房頂上張望鹦筹。 院中可真熱鬧,春花似錦址貌、人聲如沸铐拐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)遍蟋。三九已至,卻和暖如春螟凭,著一層夾襖步出監(jiān)牢的瞬間虚青,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工螺男, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留棒厘,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,247評(píng)論 3 371
  • 正文 我出身青樓下隧,卻偏偏與公主長(zhǎng)得像奢人,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子淆院,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,979評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容

  • 編碼問(wèn)題一直困擾著開發(fā)人員何乎,尤其在 Java 中更加明顯,因?yàn)?Java 是跨平臺(tái)語(yǔ)言土辩,不同平臺(tái)之間編碼之間的切換...
    x360閱讀 2,480評(píng)論 1 20
  • 可以看我的博客 lmwen.top 或者訂閱我的公眾號(hào) 簡(jiǎn)介有稍微接觸python的人就會(huì)知道支救,python中...
    ayuLiao閱讀 3,117評(píng)論 1 5
  • 為什么要編碼 不知道大家有沒(méi)有想過(guò)一個(gè)問(wèn)題,那就是為什么要編碼拷淘?我們能不能不編碼搂妻?要回答這個(gè)問(wèn)題必須要回到計(jì)算機(jī)是...
    艾小天兒閱讀 17,320評(píng)論 0 2
  • 編碼規(guī)則 如果你已經(jīng)閱讀了JavaHipster 1中references提到的兩篇文章,你應(yīng)該明白:從字符集到編...
    褲lue閱讀 1,541評(píng)論 2 1
  • 似曾相識(shí)是一種什么感覺(jué)辕棚,大抵是他說(shuō)一句欲主,當(dāng)時(shí)沒(méi)有感覺(jué),后來(lái)驚覺(jué)為何如此熟悉逝嚎,就像原本就來(lái)自記憶深處似的扁瓢。或許已經(jīng)漸...
    云漫漫閱讀 248評(píng)論 0 0