<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      徹底擺脫亂碼的困惑

      這世上為什么要有亂碼這個東西...

      先給大家出個思考題吧,一個漢字占多少字節(jié)?是不是網(wǎng)上搜出的答案五花八門,那么讀完本篇文章,我希望你至少可以準(zhǔn)確知道這個問題的答案,我覺得就算是收獲

      計算機(jī)是用 0 和 1 這種二進(jìn)制形式,來表示一切信息的。所以它需要對所有的信息進(jìn)行編碼,對整數(shù)、浮點數(shù)進(jìn)行編碼,對字符串進(jìn)行編碼,對聲音、圖片、視頻進(jìn)行編碼。每一種編碼都可以深入研究來品味,比如人們發(fā)明出補(bǔ)碼來使計算機(jī)的減法變成加法,還有各種將聲音、圖片等看似不可能的媒體信息編碼成 0 和 1。一切都很美妙,唯獨字符編碼很討人厭,往往程序員們都不愿意碰,因為它實在是太亂了。

      那今天就由我來幫你理一理。

      一、什么是編碼

      這個問題很重要

      編碼是把數(shù)據(jù)從一種形式轉(zhuǎn)換為另外一種形式的過程,而解碼則是編碼的你過程。

      注意,這里可沒有說計算機(jī)喲,所以編碼是一個更大的概念,比如我們每個人都有名字,那你的名字就是你這個人的一種編碼。你還有身份證號,那你的身份證號又是你的一種編碼。別小看這個簡單的例子,它能解釋你經(jīng)常混淆的兩個概念。

      二、字符集與字符編碼

      字符集是一個系統(tǒng)支持的所有抽象字符的集合,它是各種文字和符號的總稱,比如 ASCII 字符集、GBK 字符集,這就好比剛剛說的所有人這個集合。

      字符編碼則是怎么把字符集里的這些字符一一用二進(jìn)制表示的一個字典,或者說一個函數(shù),比如 ASCll 字符編碼、GBK 字符編碼,這就好比剛剛說的名字表示法身份證號表示法

      咦?ASCII 字符集對應(yīng)的編碼方式是 ASCII 字符編碼,GBK 字符集對應(yīng)的編碼方式是 GBK 字符編碼?沒錯,通常來說,字符集同時定義了一套同名的字符編碼規(guī)則。有人就有疑問了,那人這個字符集,不是可以用名字和身份證號兩種字符編碼么?是的,字符也可以,比如 Unicode 字符集,就可以用 UTF-8、UTF-16 等多種字符編碼來表示。

      還需要注意的一點是,在計算機(jī)的世界里,不會有像名字表示法這樣,一個名字可能對應(yīng)好多人的情況,所以名字表示法在字符編碼這里,就不是一個好的字符編碼方式,自然也不會有人廣泛采用了。

      三、字符編碼的起源 ASCII

      世界上第一份字符集和編碼標(biāo)準(zhǔn),顯然是由美國人起草的,就是大名鼎鼎的 ASCII,一共包含了 128 個字符以及對應(yīng)的二進(jìn)制,比如小寫字母 a 對應(yīng) 01100001。這 128 個字符包括了可顯示的 26 個字母(大小寫)、10 個數(shù)字、標(biāo)點符號以及特殊的控制符,也就是英語與西歐語言中常見的字符,這 128 個字符用一個字節(jié)(可表示 256 個字符)來表示綽綽有余,所以當(dāng)時只用了 7 位,還留了一個最高位當(dāng)做奇偶校驗。不奇怪,英語國家的人覺得這真的足夠了,假如世界上所有人都用英語,那字符編碼真的超級簡潔,也就不會有什么亂碼問題和這篇文章了。

      每一種字符編碼最好的描述方式就是簡單粗暴的一個字典,或者說一張表,比如 ASCII,沒什么可解釋的,它就是一張表。編碼就從右往左看,解碼就從左往右看。詳見附錄 ASCII。

      四、字符編碼開始初步發(fā)展(歐洲)

      EASCII:擴(kuò)展的 ASCII

      我們說 ASCII 發(fā)生于美國,因為一開始只有美國有計算機(jī),所以 ASCII 足夠了。可是隨著計算機(jī)的普及,西歐等國家首先開始使用(注意這時候還沒有中國)。西歐語言的字符雖然沒有中文這么多,但有很多字符是 ASCII 表示不了的。于是他們就把 ASCII 擴(kuò)充變成了 EASCII,這擴(kuò)充的包括希臘字母、特殊的拉丁符號等。由于 ASCII 只占了 7 位,所以 EASCII 把第 8 位利用起來,仍然是一個字節(jié)來表示,這時表示的字符個數(shù)是 256。

      但 EASCII 并沒有成功,西歐國家以及各個 PC 廠商各自定義出了好多不同的編碼字符集,這時候你自然就能想到,一定有一個組織站出來統(tǒng)一這個混亂的局面,制定一個標(biāo)準(zhǔn),這個組織就是國際標(biāo)準(zhǔn)化組織 ISO國際電工委員會 IEC

      ISO-8859

      這兩個組織制定了一系列的 8 位字符集標(biāo)準(zhǔn),叫做 ISO-8859。請注意,這叫一系列,我們常說的 ISO-8859-1 才是一個字符集標(biāo)準(zhǔn),只是 ISO-8859 系列中的一個。之所以定一個系列,因為那時候還想著用單字節(jié)來編碼,但除去 ASCII 占有的 0x00~0x7F,就只剩下 0x80~0xFF 可以使用了,比如將ISO-8859-1,就是向下兼容 ASCII 的字符集標(biāo)準(zhǔn),其編碼范圍是 0x000xFF,0x000x7F 之間完全和 ASCII 一致,0x80~0x9F 之間是控制字符,0xA0~0xFF 之間是文字符號。

      各個國家的符號都容納進(jìn)來顯然是不夠的,于是就分成了好多個版本,你是哪個國家的就用哪個。我們之所以經(jīng)常提到 ISO-8859-1,是因為它適用于西歐國家,而英國就是西歐國家。

      以下是全部的 ISO-8859 系列

      標(biāo)準(zhǔn)名稱 別名 適用范圍
      ISO/IEC 8859-1 Latin-1 西歐語言
      ISO/IEC 8859-2 Latin-2 中歐語言
      ISO/IEC 8859-3 Latin-3 南歐語言。世界語也可用此字符集顯示。
      ISO/IEC 8859-4 Latin-4 北歐語言
      ISO/IEC 8859-5 Cyrillic 斯拉夫語言
      ISO/IEC 8859-6 Arabic 阿拉伯語
      ISO/IEC 8859-7 Greek 希臘語
      ISO/IEC 8859-8 Hebrew 希伯來語(視覺順序)
      ISO/IEC 8859-8-I Hebrew-I 希伯來語(邏輯順序)
      ISO/IEC 8859-9 Latin-5 或 Turkish 它把 Latin-1 的冰島語字母換走,加入土耳其語字母
      ISO/IEC 8859-10 Latin-6 或 Nordic 北日耳曼語支,用來代替 Latin-4
      ISO/IEC 8859-11 Thai 泰語,從泰國的 TIS620 標(biāo)準(zhǔn)字集演化而來。
      ISO/IEC 8859-13 Latin-7 或 Baltic Rim 波羅的語族
      ISO/IEC 8859-14 Latin-8 或 Celtic 凱爾特語族
      ISO/IEC 8859-15 Latin-9 西歐語言,加入 Latin-1 欠缺的芬蘭語字母和大寫法語重音字母,以及歐元(€)符號。
      ISO/IEC 8859-16 Latin-10 東南歐語言。主要供羅馬尼亞語使用,并加入歐元符號。

      我們看到,ISO-8859-1 又叫做 Latin-1,所以現(xiàn)在你應(yīng)該知道,有的地方比如 MySQL 里的字符集顯示 Latin-1,不要陌生,他只是 ISO-8859-1 的別名。

      還是那句話,字符編碼就是一個字典或者對照表,說什么都不如列個表實在,ISO-8859-1 的對照表(只列出擴(kuò)展了 ASCII 的部分)詳見附錄 ISO-8859-1

      五、字符編碼繼續(xù)發(fā)展(來中國了)

      GB2312

      計算機(jī)開水普及到了中國,于是一切就不一樣了。原本用一個字節(jié)就解決所有的符號編碼,在中國是行不通的。于是 1981 年國家標(biāo)準(zhǔn)化管理委員會定了一套字符集叫 GB2312,每個漢字符號由兩個字節(jié)組成,注意!這里變成了兩個字節(jié)。理論上它可以表示 65536 個字符,不過它只收錄了 7445 個字符,6763 個漢字和 682 個其他字符,同時它能夠兼容 ASCII。

      GBK

      GB2312 所收錄的漢字已經(jīng)覆蓋中國大陸 99.75% 的使用頻率,但是對一些罕見的字和繁體字還有很多少數(shù)民族使用的字符都沒法處理,于是后來就在 GB2312 的基礎(chǔ)上創(chuàng)建了一種叫 GBK 的字符編碼,GBK 不僅收錄了 27484 個漢字,同時還收錄了藏文、蒙文、維吾爾文等主要的少數(shù)民族文字。GBK 是利用了 GB2312 中未被使用的編碼空間上進(jìn)行擴(kuò)充,所以它能完全兼容 GB2312 和 ASCII。

      BIG5

      臺灣地區(qū)繁體中文標(biāo)準(zhǔn)字符集,采用雙字節(jié)編碼,共收錄 13053 個中文字,1984 年實施。

      GB18030 編碼

      2000 年 3 月 17 日發(fā)布的漢字編碼國家標(biāo)準(zhǔn),是對 GBK 編碼的擴(kuò)充,覆蓋中文、日文、朝鮮語和中國少數(shù)民族文字,其中收錄 27484 個漢字。GB18030 字符集采用單字節(jié)、雙字節(jié)和四字節(jié)三種方式對字符編碼。兼容 GBK 和 GB2312 字符集。

      中文字符集總結(jié)

      簡單總結(jié)下上面的就是,ASCII < GB2312 < GBK < GB18030,后者是前者的擴(kuò)充,也即兼容了前者。然后 BIG5 是臺灣字符集,單獨的一套。

      中文字符集圖示

      這里拿最常用的 GBK 編碼舉例,GBK 的中文編碼是雙字節(jié)來表示的,英文編碼是用 ASCII 碼表示的,既用單字節(jié)表示。但 GBK 編碼表中也有英文字符的雙字節(jié)表示形式,所以英文字母可以有 2 種 GBK 表示方式。為區(qū)分中文,將其最高位都定成 1。英文單字節(jié)最高位都為 0。當(dāng)用 GBK 解碼時,若高字節(jié)最高位為 0,則用 ASCII 碼表解碼;若高字節(jié)最高位為 1,則用 GBK 編碼表解碼。你可以看到上圖中第一個字節(jié)在 00~7F(二進(jìn)制 00000000~01111111,所以第一位是 0) 之間的都是 ASCII。

      理論上說,中文字符編碼也應(yīng)該列一個對照表,無奈它實在是太多了,不但漢字?jǐn)?shù)量多,而且編碼方式也多。所以這里只列一下數(shù)量最少的 GB2312 ,而且用鏈接的形式給你。

      GB2312 簡體中文編碼表

      六、字符編碼終極發(fā)展(遍布全球)

      Unicode

      跟 ISO-8859 的出現(xiàn)原因一樣,只不過這次范圍擴(kuò)大到了全世界。當(dāng)然世界各國都有自己國家的字符編碼發(fā)展歷史,這里就沒必要一一展開了。1991 年,國際標(biāo)準(zhǔn)化組織和統(tǒng)一碼聯(lián)盟組織退出了 Unicode 項目,目的就是同一全世界的所有字符。

      你可能知道 Unicode 分 UTF-8、UTF-16、UCS-2 等,而 ISO-8859 也分 ISO-8859-1、ISO-8859-2……你會不會覺得它們是一樣的道理呢?錯!

      • ISO-8859 是一個字符集的系列,分成 ISO-8859-1、ISO-8859-2 等好多字符集,而每個字符集對應(yīng)的編碼方式就是 ISO-8859-1 編碼、ISO-8859-2 編碼,是一對一的關(guān)系。
      • Unicode 本身就是一個字符集,是全世界所有字符的合集,它并不是字符集系列。而 Unicode 這個字符集特殊的地方在于,他的編碼方式不叫 Unicode 編碼,它的編碼方式有很多種,分別是 UTF-8 編碼、UTF-16 編碼等。

      所以字符集系列和字符集的區(qū)別,最好的例子就是 ISO-8859;而字符集和字符編碼的區(qū)別,最好的例子就是 Unicode。

      捋清了這個關(guān)系,下面我們就可以詳細(xì)說說大家心心念念的 Unicode 了。Unicode 本身并沒有規(guī)定一個字符究竟是怎么編碼,甚至都沒有規(guī)定用幾個字節(jié)表示,所以也叫可變長度字符編碼。Unicode 只規(guī)定了每個字符對應(yīng)到唯一的代碼值(code point),代碼值從 0000~10FFFF 共 1114112 個值,你曾經(jīng)看到的很討人厭的 \u0300 這種,就是 Unicode 的代碼值,這種代碼值要想變成真正存儲在機(jī)器里的字符串,一定要進(jìn)行某種編碼,如下。

      ustr = \u0030;
      str = ustr.encode("utf-8")
      

      真正存儲的時候需要多少個字節(jié)是由具體的編碼格式?jīng)Q定的。比如:字符 「A」用 UTF-8 的格式編碼來存儲就只占用 1 個字節(jié),用 UTF-16 就占用 2 個字節(jié),而用 UTF-32 存儲就占用 4 個字節(jié)。而 UTF-8 本身,又不是固定長度的,也是可變長度的。

      Unicode UTF-8 byte 數(shù) 備注
      0000~007F 0XXX XXXX 1
      0080~07FF 110X XXXX 10XX XXXX 2
      0800~FFFF 1110 XXXX 10XX XXXX 10XX XXXX 3 基本定義范圍:0~FFFF
      1 0000~1F FFFF 1111 0XXX 10XX XXXX 10XX XXXX 10XX XXXX 4 Unicode6.1 定義范圍:0~10 FFFF

      所以從這里你可以看出,一般一種編碼方式是如何兼容其他編碼的,又是如何可變長度的。UTF-8 編碼的第一位如果是 0,則只有一個字節(jié),跟 ASCII 編碼完全一樣,所以兼容了。如果是 110 開頭,則是兩個字節(jié),以此類推如上表所示。所以開頭幾位的值,是編碼本身,同時又是判斷是幾個字節(jié)數(shù)的推碼,可謂是一箭雙雕。這種設(shè)計頗有點像 CPU 中的相聯(lián)存儲器的概念。

      所以如果再有人問你這個問題:UTF-8 占幾個字節(jié)漢字到底占幾個字節(jié)?你就可以這樣專業(yè)而又不裝逼的回答:

      首先漢字占幾個字節(jié)這個問題本身就不明確,應(yīng)該問 Unicode 字符集中的漢字用 UTF-8 編碼方式編碼,占幾個字節(jié)?

      那這個問題就演化成了 UTF-8 占幾個字節(jié)。UTF-8 是可變長度字符編碼,所以只能說占 1~4 個字節(jié)。

      • 單字節(jié)可編碼的 Unicode 范圍:\u0000\u007F(0127)
      • 雙字節(jié)可編碼的 Unicode 范圍:\u0080\u07FF(1282047)
      • 三字節(jié)可編碼的 Unicode 范圍:\u0800\uFFFF(204865535)
      • 四字節(jié)可編碼的 Unicode 范圍:\u10000\u1FFFFF(655362097151)

      那基于各種歷史的或者是合理性原因,人們把占用 1 個字節(jié)的給了 ASCII;占 2 個字節(jié)的給了拉丁文、希臘文、西里爾字母、亞美尼亞語、希伯來文等;占 3 個字節(jié)的給了大部分漢字,基本等同于 GBK,含 21000 多個漢字;占 4 個字節(jié)的中日韓超大字符集里面的漢字,有 5 萬多個。

      所以,漢字占三個字節(jié)這句話,應(yīng)該說成

      Unicode 字符集中的大部分漢字,如果用 UTF-8 編碼的話,是占 3 個字節(jié)的。而 UTF-8 編碼本身,是 1~4 個字節(jié)的可變長度字符編碼。

      七、字符編碼的總結(jié)

      按時間線

      • 美國線:ASCII --> EASCII --> ISO-8859 --> Unicode
      • 中國線:GB2312 --> GBK --> GB18030 --> Unicode
      • 他國線:... ... --> Unicode

      按含義

      • 字符集系列(對應(yīng) n 多個字符集):ISO-8859 系列
      • 字符集(對應(yīng) n 多個字符編碼):ASCII、ISO-8859-1、GBK、Unicode
      • 字符編碼:ASCII、ISO-8859-1、GBK、UTF-8、UTF-16

      按字節(jié)數(shù)

      • 單字節(jié):ASCII、ISO-8859 系列
      • 雙字節(jié):GB2312、GBK
      • 可變字節(jié):UTF-8、UTF-16

      八、為什么會產(chǎn)生亂碼

      前面說過,編碼和解碼,就是一個查表的過程,正著查是二進(jìn)制的值到字符,反著查是字符到二進(jìn)制的數(shù)值。所謂亂碼,就是編碼和解碼查的不是一張表嘛。就好比你叫你丈夫的爹為“公公”,你是查現(xiàn)代漢語詞典編碼出的“公公”兩個字,人家爸爸卻拿著古代漢語詞典來解碼你這個“公公”的含義,這不亂才怪嘛。

      自己構(gòu)造一個亂碼很簡單,我們用 UTF-8 來編碼一個“你好”這兩個字,再用 GBK 解碼來閱讀,看看會怎么樣。

      1. 首先新建一個 txt 文件,就叫【亂碼.txt】吧,然后用二進(jìn)制方式打開它(我用的是 Notepad++,下載了 Hex-Editor 插件)。

      2. 我們查 UTF-8 編碼字典,發(fā)現(xiàn)你好兩個字的編碼是“E4BDA0”、“E5A5BD”,我們將編碼輸入。

      3. 好吧你說這哪是 2 進(jìn)制啊,這不是 16 進(jìn)制么。那我們就直接一點,用純 2 進(jìn)制的方式輸入,“111001001011110110100000”,“111001011010010110111101”。

      存在計算機(jī)里都一樣

      1. 返回正常的文本狀態(tài),選擇用 UTF-8 編碼方式查看,發(fā)現(xiàn)是正常的“你好”兩個字。但如果切換成 GBK(這里我選擇了 GB2312,一樣的),就變成了奇怪的文字。

      1. 這很好理解,UTF-8 編碼漢字是 3 個字節(jié),剛剛我們編碼了“你好”,對應(yīng)的字節(jié)序列是 “E4BDA0”、“E5A5BD”,一共 6 個字節(jié)。GBK 編碼漢字是 2 個字節(jié),于是解讀成了 “E4BD“、”A0E5“、”A5BD”,三個漢字。那我們查 GBK 碼表:

      你有沒有發(fā)現(xiàn),居然跟我們看到的是一樣的!這還是比較有好的亂碼,起碼還能對應(yīng)上真正碼表中存在的漢字。有的亂碼字節(jié)數(shù)都不對,或者干脆碼表中查不到,就難看極了。這就要看各個不同的文本查看軟件怎么處理了,比如我 GBK 本來是雙字節(jié)的,我硬生生把一個字的后一個字節(jié)刪了,這種情況 Notepad++ 還算友好,可以讓你看到是因為少了一個字節(jié)出的問題,如果用記事本打開,就是一個大寫的 “?”。

      編碼我們都理解了,就是最終寫在計算機(jī)內(nèi)存里的 01010 字節(jié)序列。而對于解碼,似乎還是有一點迷惑,解碼解成了什么呢?要相信自己的判斷,沒錯,解碼就是解成了我們眼睛看到的這些東西,他們的本質(zhì)就是屏幕上顯示的光點。比如說漢字,其實解碼我們所查的表,最終對應(yīng)的就是一個 n*n 的矩陣,最終再經(jīng)過一些列的轉(zhuǎn)換,由串口輸出到顯示屏上,矩陣中的 1 就代表有,0 就代表無,經(jīng)過放大縮小等線性變換,最終達(dá)到屏幕上的一個個小光點上,就變成了我們看到的字。老一輩的計算機(jī)從業(yè)者,有很多人力需要去造這張表,就是把每個編碼對應(yīng)的這個矩陣畫出來,最終存成字庫。如果你聽老一輩的計算機(jī)從業(yè)者講述,將聽到很多關(guān)于這里的故事,像“區(qū)位碼”,這里我就不展開說了,其實也是因為沒經(jīng)歷過,不太了解。

      九、如何解決亂碼

      上一環(huán)節(jié)我給你展示了一個文本文件如何產(chǎn)生了亂碼,那如何解決文本文件的編碼呢,很簡單,保存的時候用什么格式編碼保存的,讀取的時候就用什么時候讀。比如 Notepad++ 就很清晰,保存和讀取都在【編碼】這個菜單欄里。

      對于記事本,我們似乎沒看到編碼這一項,其實如果你選擇另存為,一般會有四個編碼選項讓你選擇,分別是 ANSI、Unicode、Unicode big endian、UTF-8。如果你不選擇的話,默認(rèn)保存是用 ANSI,那 windows 平臺一般是指的 GBK

      這里你可能會困惑,剛剛不是說了 Unicode 不是字符集編碼,而只是字符集么,這里怎么又出現(xiàn)在編碼了。沒錯,這就是字符編碼比較亂的地方之一,命名不規(guī)范,有很多潛規(guī)則。比如這個記事本的 Unicode:Windows 平臺下默認(rèn)的 Unicode 編碼為 Little Endian 的 UTF-16,實際上它還是指的是一個具體的編碼格式,只不過被潛規(guī)則在 Windows 平臺下了,讓很多人誤以為 Unicode 就是特指某種具體的編碼方式。

      瀏覽器

      剛剛解釋了下記事本的亂碼解決,其實所有工具都是一樣的,只要有文本閱讀的地方,一般都會有設(shè)置編碼的地方。那么我們來看一下最常見也最容易出錯的瀏覽器。我們打開一個網(wǎng)頁發(fā)現(xiàn)是亂碼,這尤其經(jīng)常發(fā)生在我們開發(fā)測試階段,那么我們先拋離服務(wù)端,單純創(chuàng)建一個亂碼的頁面。

      用 Notepad++ 寫一個以 UTF-8 編碼的文件 test.html:

      <!DOCTYPE HTML>
      <html>
          <head></head>
          <body>
              你好
          </body>
      </html>
      

      用 IE 瀏覽器打開,直接亂碼:

      而如果我們重新用 GBK 編碼寫一個一模一樣的文件,再用 IE 打開,正常。這是為什么呢?原因很簡單,IE 瀏覽器默認(rèn)用 GBK 去解碼一個 HTML。這又是一個潛規(guī)則。

      而我們怎么才能讓它顯示正確呢?你可以強(qiáng)行改瀏覽器的編碼方式,但你搞一個服務(wù),總不能讓用戶去做這個事情吧?一個個試哪個編碼方式正確?即使瀏覽器功能強(qiáng)大到可以智能分析編碼,也最好有一個標(biāo)識來告訴瀏覽器這個 HTML 是如何編碼的,這個標(biāo)識就是:

      <meta charset = "utf-8"/>
      

      把它加載 header 中:

      <!DOCTYPE HTML>
      <html>
          <head>
              <meta charset = "utf-8"/>
          </head>
          <body>
              你好
          </body>
      </html>
      

      再用 IE 瀏覽器打開,正常!

      那么我們就知道了,頁面產(chǎn)生亂碼,不是我們的問題,要么是服務(wù)端沒有設(shè)置這個 meta charset,要么就是服務(wù)端設(shè)置了,但實際上編碼響應(yīng)流的時候卻用了其他編碼方式。當(dāng)然我們也能自己強(qiáng)行解決,那就是設(shè)置瀏覽器的編碼方式,不同瀏覽器設(shè)置編碼方式的位置不一樣,而且我個人感覺也很難找,不同瀏覽器的默認(rèn)編碼方式也不同,而且還有可能有 Unicode 指的是 UTF-8 這樣的潛規(guī)則。所以為了徹底杜絕這個問題,還是在 HTML 文件里面告知為好。

      服務(wù)器

      既然瀏覽的頁面亂碼怪服務(wù)端,那我就不得不說說服務(wù)端這邊的事。

      我們寫一個 Spring Boot 程序:

      @SpringBootApplication
      @Controller
      public class JavamateSpringbootApplication {
      
          public static void main(String[] args) {
              SpringApplication.run(JavamateSpringbootApplication.class, args);
          }
      
          @RequestMapping("hello")
          @ResponseBody
          public String hello() {
              return "你好";
          }
      }
      

      瀏覽器訪問 /hello,完美顯示“你好”,并沒有亂碼。

      正因為 Spring Boot 為我們做了太多事,才這么容易發(fā)生不亂碼的情況。其實與其說為什么會亂碼,不如解釋解釋為什么這段代碼沒有亂碼。

      首先沒有亂碼,一定是編解碼用的是同一套。那編碼是什么呢,這里就又涉及到潛規(guī)則了,Spring Boot 默認(rèn)情況下,@ResponseBody 會用 UTF-8 對字符串進(jìn)行編碼,而且會為響應(yīng)體設(shè)置一個相應(yīng)頭:

      Content-Type: text/javascript; charset=UTF-8
      

      解碼方面,IE 瀏覽器默認(rèn)是 GBK,但你響應(yīng)體里有這個頭了,那 IE 會改成用 UTF-8 解碼。

      不知道你有沒有經(jīng)歷過 Tomcat 時代的 ISO-8859-1 亂碼的時代,那時候沒有這些強(qiáng)大的開發(fā)框架,好多地方可能要 response 直接 write 數(shù)據(jù)出去,而 Tomcat 此時的默認(rèn)編碼是 ISO-8859-1。所以那時候好多地方都需要手動改成 UTF-8。由于 UTF-8 漸漸變成了國際標(biāo)準(zhǔn),Spring Boot 框架也將內(nèi)嵌的 Tomcat 默認(rèn)編碼格式改成了 UTF-8。

      那我們怎么搞出一個亂碼呢?很簡單,我們用默認(rèn)編碼格式為 ISO-8859-1 的 Response 直接 write 出去,而不依賴于框架。

      @RequestMapping("hello2")
      public void hello2(HttpServletResponse response) throws IOException {
          PrintWriter writer = response.getWriter();
          writer.println("你好");
          writer.flush();
      }
      

      瀏覽器打開,直接亂碼。

      其實更直觀的寫法應(yīng)該是這樣,拋開所有默認(rèn)的外套:

      @RequestMapping("hello2")
      public void hello2(HttpServletResponse response) throws IOException {
          response.setCharacterEncoding("gbk");
          response.addHeader("Content-Type", "text/html");
          ServletOutputStream out = response.getOutputStream();
          out.write("你好".getBytes("utf-8"));
          out.flush();
      }
      

      瀏覽器打開,看到了我們熟悉的亂碼。

      浣犲ソ
      

      我們看到代碼中,直接表達(dá)了:將“你好”用 UTF-8 格式編碼,并通過響應(yīng)頭告訴瀏覽器,用 GBK 的方式解碼。這自然就亂碼了。

      現(xiàn)在的服務(wù)端框架,已經(jīng)達(dá)成了用 UTF-8 作為編解碼標(biāo)準(zhǔn)的共識,而且 String 的 getBytes 方法默認(rèn)的也是 UTF-8,也可以通過 file.encoding 參數(shù)配置。所以現(xiàn)在基本不用擔(dān)心亂碼問題了。在 Tomcat 亂碼滿天飛的時代,解決亂碼問題也無非是:

      • 看字符串本身的編碼
      • 看設(shè)置回響應(yīng)頭的編碼
      • 看 HTML 文件的 meta 屬性的編碼

      附錄后文末有驚喜

      十、附錄

      ASCII 和 ISO-8859-1 的編碼表

      ASCII

      Bin Oct Dec Hex 縮寫/字符 解釋
      (二進(jìn)制) (八進(jìn)制) (十進(jìn)制) (十六進(jìn)制)
      0000 0000 0 0 0x00 NUL(null) 空字符
      0000 0001 1 1 0x01 SOH(start of headline) 標(biāo)題開始
      0000 0010 2 2 0x02 STX (start of text) 正文開始
      0000 0011 3 3 0x03 ETX (end of text) 正文結(jié)束
      0000 0100 4 4 0x04 EOT (end of transmission) 傳輸結(jié)束
      0000 0101 5 5 0x05 ENQ (enquiry) 請求
      0000 0110 6 6 0x06 ACK (acknowledge) 收到通知
      0000 0111 7 7 0x07 BEL (bell) 響鈴
      0000 1000 10 8 0x08 BS (backspace) 退格
      0000 1001 11 9 0x09 HT (horizontal tab) 水平制表符
      0000 1010 12 10 0x0A LF (NL line feed, new line) 換行鍵
      0000 1011 13 11 0x0B VT (vertical tab) 垂直制表符
      0000 1100 14 12 0x0C FF (NP form feed, new page) 換頁鍵
      0000 1101 15 13 0x0D CR (carriage return) 回車鍵
      0000 1110 16 14 0x0E SO (shift out) 不用切換
      0000 1111 17 15 0x0F SI (shift in) 啟用切換
      0001 0000 20 16 0x10 DLE (data link escape) 數(shù)據(jù)鏈路轉(zhuǎn)義
      0001 0001 21 17 0x11 DC1 (device control 1) 設(shè)備控制 1
      0001 0010 22 18 0x12 DC2 (device control 2) 設(shè)備控制 2
      0001 0011 23 19 0x13 DC3 (device control 3) 設(shè)備控制 3
      0001 0100 24 20 0x14 DC4 (device control 4) 設(shè)備控制 4
      0001 0101 25 21 0x15 NAK (negative acknowledge) 拒絕接收
      0001 0110 26 22 0x16 SYN (synchronous idle) 同步空閑
      0001 0111 27 23 0x17 ETB (end of trans. block) 結(jié)束傳輸塊
      0001 1000 30 24 0x18 CAN (cancel) 取消
      0001 1001 31 25 0x19 EM (end of medium) 媒介結(jié)束
      0001 1010 32 26 0x1A SUB (substitute) 代替
      0001 1011 33 27 0x1B ESC (escape) 換碼(溢出)
      0001 1100 34 28 0x1C FS (file separator) 文件分隔符
      0001 1101 35 29 0x1D GS (group separator) 分組符
      0001 1110 36 30 0x1E RS (record separator) 記錄分隔符
      0001 1111 37 31 0x1F US (unit separator) 單元分隔符
      0010 0000 40 32 0x20 (space) 空格
      0010 0001 41 33 0x21 ! 嘆號
      0010 0010 42 34 0x22 " 雙引號
      0010 0011 43 35 0x23 # 井號
      0010 0100 44 36 0x24 $ 美元符
      0010 0101 45 37 0x25 % 百分號
      0010 0110 46 38 0x26 & 和號
      0010 0111 47 39 0x27 ' 閉單引號
      0010 1000 50 40 0x28 ( 開括號
      0010 1001 51 41 0x29 ) 閉括號
      0010 1010 52 42 0x2A * 星號
      0010 1011 53 43 0x2B + 加號
      0010 1100 54 44 0x2C , 逗號
      0010 1101 55 45 0x2D - 減號/破折號
      0010 1110 56 46 0x2E . 句號
      0010 1111 57 47 0x2F / 斜杠
      0011 0000 60 48 0x30 0 字符 0
      0011 0001 61 49 0x31 1 字符 1
      0011 0010 62 50 0x32 2 字符 2
      0011 0011 63 51 0x33 3 字符 3
      0011 0100 64 52 0x34 4 字符 4
      0011 0101 65 53 0x35 5 字符 5
      0011 0110 66 54 0x36 6 字符 6
      0011 0111 67 55 0x37 7 字符 7
      0011 1000 70 56 0x38 8 字符 8
      0011 1001 71 57 0x39 9 字符 9
      0011 1010 72 58 0x3A : 冒號
      0011 1011 73 59 0x3B ; 分號
      0011 1100 74 60 0x3C < 小于
      0011 1101 75 61 0x3D = 等號
      0011 1110 76 62 0x3E > 大于
      0011 1111 77 63 0x3F ? 問號
      0100 0000 100 64 0x40 @ 電子郵件符號
      0100 0001 101 65 0x41 A 大寫字母 A
      0100 0010 102 66 0x42 B 大寫字母 B
      0100 0011 103 67 0x43 C 大寫字母 C
      0100 0100 104 68 0x44 D 大寫字母 D
      0100 0101 105 69 0x45 E 大寫字母 E
      0100 0110 106 70 0x46 F 大寫字母 F
      0100 0111 107 71 0x47 G 大寫字母 G
      0100 1000 110 72 0x48 H 大寫字母 H
      0100 1001 111 73 0x49 I 大寫字母 I
      1001010 112 74 0x4A J 大寫字母 J
      0100 1011 113 75 0x4B K 大寫字母 K
      0100 1100 114 76 0x4C L 大寫字母 L
      0100 1101 115 77 0x4D M 大寫字母 M
      0100 1110 116 78 0x4E N 大寫字母 N
      0100 1111 117 79 0x4F O 大寫字母 O
      0101 0000 120 80 0x50 P 大寫字母 P
      0101 0001 121 81 0x51 Q 大寫字母 Q
      0101 0010 122 82 0x52 R 大寫字母 R
      0101 0011 123 83 0x53 S 大寫字母 S
      0101 0100 124 84 0x54 T 大寫字母 T
      0101 0101 125 85 0x55 U 大寫字母 U
      0101 0110 126 86 0x56 V 大寫字母 V
      0101 0111 127 87 0x57 W 大寫字母 W
      0101 1000 130 88 0x58 X 大寫字母 X
      0101 1001 131 89 0x59 Y 大寫字母 Y
      0101 1010 132 90 0x5A Z 大寫字母 Z
      0101 1011 133 91 0x5B [ 開方括號
      0101 1100 134 92 0x5C \ 反斜杠
      0101 1101 135 93 0x5D ] 閉方括號
      0101 1110 136 94 0x5E ^ 脫字符
      0101 1111 137 95 0x5F _ 下劃線
      0110 0000 140 96 0x60 ` 開單引號
      0110 0001 141 97 0x61 a 小寫字母 a
      0110 0010 142 98 0x62 b 小寫字母 b
      0110 0011 143 99 0x63 c 小寫字母 c
      0110 0100 144 100 0x64 d 小寫字母 d
      0110 0101 145 101 0x65 e 小寫字母 e
      0110 0110 146 102 0x66 f 小寫字母 f
      0110 0111 147 103 0x67 g 小寫字母 g
      0110 1000 150 104 0x68 h 小寫字母 h
      0110 1001 151 105 0x69 i 小寫字母 i
      0110 1010 152 106 0x6A j 小寫字母 j
      0110 1011 153 107 0x6B k 小寫字母 k
      0110 1100 154 108 0x6C l 小寫字母 l
      0110 1101 155 109 0x6D m 小寫字母 m
      0110 1110 156 110 0x6E n 小寫字母 n
      0110 1111 157 111 0x6F o 小寫字母 o
      0111 0000 160 112 0x70 p 小寫字母 p
      0111 0001 161 113 0x71 q 小寫字母 q
      0111 0010 162 114 0x72 r 小寫字母 r
      0111 0011 163 115 0x73 s 小寫字母 s
      0111 0100 164 116 0x74 t 小寫字母 t
      0111 0101 165 117 0x75 u 小寫字母 u
      0111 0110 166 118 0x76 v 小寫字母 v
      0111 0111 167 119 0x77 w 小寫字母 w
      0111 1000 170 120 0x78 x 小寫字母 x
      0111 1001 171 121 0x79 y 小寫字母 y
      0111 1010 172 122 0x7A z 小寫字母 z
      0111 1011 173 123 0x7B { 開花括號
      0111 1100 174 124 0x7C \
      0111 1101 175 125 0x7D } 閉花括號
      0111 1110 176 126 0x7E ~ 波浪號
      0111 1111 177 127 0x7F DEL (delete) 刪除

      ISO-8859-1

      DEC OCT HEX BIN Symbol Description
      128 200 80 10000000 Euro sign
      129 201 81 10000001
      130 202 82 10000010 Single low-9 quotation mark
      131 203 83 10000011 ? Latin small letter f with hook
      132 204 84 10000100 ? Double low-9 quotation mark
      133 205 85 10000101 Horizontal ellipsis
      134 206 86 10000110 ? Dagger
      135 207 87 10000111 ? Double dagger
      136 210 88 10001000 ? Modifier letter circumflex accent
      137 211 89 10001001 Per mille sign
      138 212 8A 10001010 ? Latin capital letter S with caron
      139 213 8B 10001011 ? Single left-pointing angle quotation
      140 214 8C 10001100 ? Latin capital ligature OE
      141 215 8D 10001101
      142 216 8E 10001110 ? Latin captial letter Z with caron
      143 217 8F 10001111
      144 220 90 10010000
      145 221 91 10010001 Left single quotation mark
      146 222 92 10010010 Right single quotation mark
      147 223 93 10010011 Left double quotation mark
      148 224 94 10010100 Right double quotation mark
      149 225 95 10010101 ? Bullet
      150 226 96 10010110 En dash
      151 227 97 10010111 Em dash
      152 230 98 10011000 ? Small tilde
      153 231 99 10011001 ? Trade mark sign
      154 232 9A 10011010 ? Latin small letter S with caron
      155 233 9B 10011011 ? Single right-pointing angle quotation mark
      156 234 9C 10011100 ? Latin small ligature oe
      157 235 9D 10011101
      158 236 9E 10011110 ? Latin small letter z with caron
      159 237 9F 10011111 ? Latin capital letter Y with diaeresis
      160 240 A0 10100000 Non-breaking space
      161 241 A1 10100001 ? Inverted exclamation mark
      162 242 A2 10100010 Cent sign
      163 243 A3 10100011 Pound sign
      164 244 A4 10100100 ¤ Currency sign
      165 245 A5 10100101 Yen sign
      166 246 A6 10100110 | Pipe, Broken vertical bar
      167 247 A7 10100111 § Section sign
      168 250 A8 10101000 ¨ Spacing diaeresis - umlaut
      169 251 A9 10101001 ? Copyright sign
      170 252 AA 10101010 a Feminine ordinal indicator
      171 253 AB 10101011 ? Left double angle quotes
      172 254 AC 10101100 ? Not sign
      173 255 AD 10101101 Soft hyphen
      174 256 AE 10101110 ? Registered trade mark sign
      175 257 AF 10101111 ˉ Spacing macron - overline
      176 260 B0 10110000 ° Degree sign
      177 261 B1 10110001 ± Plus-or-minus sign
      178 262 B2 10110010 2 Superscript two - squared
      179 263 B3 10110011 3 Superscript three - cubed
      180 264 B4 10110100 Acute accent - spacing acute
      181 265 B5 10110101 μ Micro sign
      182 266 B6 10110110 ? Pilcrow sign - paragraph sign
      183 267 B7 10110111 · Middle dot - Georgian comma
      184 270 B8 10111000 ? Spacing cedilla
      185 271 B9 10111001 1 Superscript one
      186 272 BA 10111010 o Masculine ordinal indicator
      187 273 BB 10111011 ? Right double angle quotes
      188 274 BC 10111100 ? Fraction one quarter
      189 275 BD 10111101 ? Fraction one half
      190 276 BE 10111110 ? Fraction three quarters
      191 277 BF 10111111 ? Inverted question mark
      192 300 C0 11000000 à Latin capital letter A with grave
      193 301 C1 11000001 á Latin capital letter A with acute
      194 302 C2 11000010 ? Latin capital letter A with circumflex
      195 303 C3 11000011 ? Latin capital letter A with tilde
      196 304 C4 11000100 ? Latin capital letter A with diaeresis
      197 305 C5 11000101 ? Latin capital letter A with ring above
      198 306 C6 11000110 ? Latin capital letter AE
      199 307 C7 11000111 ? Latin capital letter C with cedilla
      200 310 C8 11001000 è Latin capital letter E with grave
      201 311 C9 11001001 é Latin capital letter E with acute
      202 312 CA 11001010 ê Latin capital letter E with circumflex
      203 313 CB 11001011 ? Latin capital letter E with diaeresis
      204 314 CC 11001100 ì Latin capital letter I with grave
      205 315 CD 11001101 í Latin capital letter I with acute
      206 316 CE 11001110 ? Latin capital letter I with circumflex
      207 317 CF 11001111 ? Latin capital letter I with diaeresis
      208 320 D0 11010000 D Latin capital letter ETH
      209 321 D1 11010001 ? Latin capital letter N with tilde
      210 322 D2 11010010 ò Latin capital letter O with grave
      211 323 D3 11010011 ó Latin capital letter O with acute
      212 324 D4 11010100 ? Latin capital letter O with circumflex
      213 325 D5 11010101 ? Latin capital letter O with tilde
      214 326 D6 11010110 ? Latin capital letter O with diaeresis
      215 327 D7 11010111 × Multiplication sign
      216 330 D8 11011000 ? Latin capital letter O with slash
      217 331 D9 11011001 ù Latin capital letter U with grave
      218 332 DA 11011010 ú Latin capital letter U with acute
      219 333 DB 11011011 ? Latin capital letter U with circumflex
      220 334 DC 11011100 ü Latin capital letter U with diaeresis
      221 335 DD 11011101 Y Latin capital letter Y with acute
      222 336 DE 11011110 T Latin capital letter THORN
      223 337 DF 11011111 ? Latin small letter sharp s - ess-zed
      224 340 E0 11100000 à Latin small letter a with grave
      225 341 E1 11100001 á Latin small letter a with acute
      226 342 E2 11100010 a Latin small letter a with circumflex
      227 343 E3 11100011 ? Latin small letter a with tilde
      228 344 E4 11100100 ? Latin small letter a with diaeresis
      229 345 E5 11100101 ? Latin small letter a with ring above
      230 346 E6 11100110 ? Latin small letter ae
      231 347 E7 11100111 ? Latin small letter c with cedilla
      232 350 E8 11101000 è Latin small letter e with grave
      233 351 E9 11101001 é Latin small letter e with acute
      234 352 EA 11101010 ê Latin small letter e with circumflex
      235 353 EB 11101011 ? Latin small letter e with diaeresis
      236 354 EC 11101100 ì Latin small letter i with grave
      237 355 ED 11101101 í Latin small letter i with acute
      238 356 EE 11101110 ? Latin small letter i with circumflex
      239 357 EF 11101111 ? Latin small letter i with diaeresis
      240 360 F0 11110000 e Latin small letter eth
      241 361 F1 11110001 ? Latin small letter n with tilde
      242 362 F2 11110010 ò Latin small letter o with grave
      243 363 F3 11110011 ó Latin small letter o with acute
      244 364 F4 11110100 ? Latin small letter o with circumflex
      245 365 F5 11110101 ? Latin small letter o with tilde
      246 366 F6 11110110 ? Latin small letter o with diaeresis
      247 367 F7 11110111 ÷ Division sign
      248 370 F8 11111000 ? Latin small letter o with slash
      249 371 F9 11111001 ù Latin small letter u with grave
      250 372 FA 11111010 ú Latin small letter u with acute
      251 373 FB 11111011 ? Latin small letter u with circumflex
      252 374 FC 11111100 ü Latin small letter u with diaeresis
      253 375 FD 11111101 y Latin small letter y with acute
      254 376 FE 11111110 t Latin small letter thorn
      255 377 FF 11111111 ? Latin small letter y with diaeresis

      逗你呢,沒什么驚喜。

      但這樣搞大家有點于心不忍

      給大家出一個題吧,1 斤 100 元的紙幣和 100 斤 1 元的紙幣,你選拿個?公眾號下期文章揭曉答案

      posted @ 2020-11-14 23:51  閃客sun  閱讀(4415)  評論(10)    收藏  舉報
      主站蜘蛛池模板: 免费看国产精品3a黄的视频| 国产色无码专区在线观看| 影音先锋啪啪av资源网站| 国产在线中文字幕精品| 老少配老妇老熟女中文普通话| 日日噜噜夜夜爽爽| 国产精品国语对白一区二区| 在线中文一区字幕对白| 久久国产欧美日韩精品图片| 精品偷拍一区二区三区| 国产成人无码免费视频在线| 国产精品一区中文字幕| 成人国产亚洲精品一区二区| www久久只有这里有精品| 久久99精品久久久久久9| 人妻在线无码一区二区三区| 免费又黄又爽又猛的毛片| 国产精品爽爽va在线观看网站| 国产精品揄拍100视频| 一区二区三区四区亚洲自拍| 国产欧美一区二区日本加勒比| 多伦县| 日韩视频一区二区三区视频| 亚洲爆乳少妇无码激情| 国产精品中文字幕一区| 国产精品美女一区二区三| 无码吃奶揉捏奶头高潮视频| av午夜福利亚洲精品福利| 2019亚洲午夜无码天堂| 国产精品天天看天天狠| 人妻体内射精一区二区三四| 免费区欧美一级猛片| 99久久国产精品无码| 蓝田县| 老太脱裤子让老头玩xxxxx| 亚洲香蕉av一区二区蜜桃| 日本高清无卡码一区二区| 国产精品中文字幕观看| 特级av毛片免费观看| 日本一区二区三区专线| 人妻激情一区二区三区四区|