HTTP封包可以承載任何語言表示的内容的。因為對HTTP來說,實體主體真實二進制資訊的容器而已。
在HTTP中為了支援國際性,伺服器傳回内容的同時需要告知用戶端文檔是用的什麼字母表和語言等資訊,這樣用戶端才能正确的解析出資訊并顯示字元。伺服器可以通過
Content-Type
中的
charset
參數和
Content-Language
首部告知用戶端字母表和語言資訊。
同時,用戶端并不是所有的字母表和語言都能進行處理,是以用戶端在發起請求的時候,也可以通過發送
Accept-Charset
和
Accept-Language
首部,告知服務端自己所能處理的編碼類型和語言。這兩個首部也支援優先級,可以通過
q
參數設定優先級。
是以,HTTP中的國際化,也就是本篇要介紹的内容主要涉及到字元集編碼(character set encoding)和語言标記(language tag)
1 字元集和HTTP
1.1 字元集的概念
所謂字元集起始就是把字元轉為二進制碼的編碼。HTTP 字元集的值說明如何把實體内容的二進制碼轉換為特定字母表中的字元。每個字元集标記都命名了一種把二進制碼轉換為字元的算法(反之亦然)。字元集标記在由 IANA 維護MIME字元集注冊機構進行了标準化。一般通過
Content-Type
中的
charset
參數進行指定。如下:
Content-Type: text/html; charset=utf-8
其中utf-8就是一種編碼算法,後面會有相關介紹。
1.2 字元集與編碼
上面說了,字元集和編碼目的就是為了将二進制資訊同我們的字元進行轉換。轉換的具體流程一般經過兩個步驟完成(這裡以将二進制資訊轉為字元過程為例):
- 首先需要将二進制資訊轉為字元代碼(某個字元集中的某個字元的特定編号);
- 得到這個代碼後,我們再跟進這個代碼從字元集中找到該代碼對應的字元。
經過上面兩個步驟,就能獲得正确的字元了。而我們上面兩個步驟都依賴于正确的
charset
值。如果該值不正确,同樣一段二進制資訊可能就會得出錯誤的字元代碼,同樣第二步中根據
charset
的值不同,字元代碼和字元的對應關系也就不同。是以平時的亂碼現象,有時候就是因為
charset
的值錯誤而引起。
charset
的值使用的标準化的MIME charset标記。比如:utf-8, iso-8895-1, gbk等。這裡不對每種編碼做叙述,後續會對一些常見的編碼方式做介紹。另外一點,該值一般來說是大小寫不敏感的,在處理的時候需要注意這點。
1.3 用戶端對字元集的處理
正常情況下,伺服器會通過在
Content-Type
首部中使用
charset
參數告知用戶端MIME字元集。但是如果伺服器沒有顯示的傳回資訊,我們用戶端可能就需要盡可能自己從文檔内容判斷出字元集。一般在HTML文檔中,會通過
<META HTTP-EQUIV="Content-Type">
描述所用字元集資訊。如下:
<HEAD>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=gbk">
<META LANG="jp">
<TITLE>A Japanese Document</TITLE>
</HEAD>
<BODY>
...
該部分類容說明該html文檔使用的
gbk
編碼。
全世界範圍類字元集編碼非常多,伺服器并不一定都是傳回的用戶端能正确處理的字元集。是以為了避免伺服器端傳回一些用戶端無法處理的字元集,用戶端在發送請求的時候,盡量通過
Accept-Charset
首部告知伺服器,我們需要或者想要什麼字元集,可以處理哪些字元集。
2 字元編碼簡介
前面我們介紹了伺服器和用戶端之間怎麼協商處理字元集。本節是簡單對字元編碼的過程的一個簡單入門介紹。
2.1 字元集術語
這裡我們将一組把一系列 8 位位元組轉換為一系列字元的規則的集合稱為字元集。其包括編碼方案和編碼後的字元集。在介紹字元集的時候會用到一下一些術語:
- 字元: 字元是指字母、數字、标點、表意文字(比如漢語)、符号,或其他文本形式的 書寫“原子”。
- 字形:字形是字元的一種表現形式,同一個字元可以有多重字形,比如同樣一個漢字,宋體和楷體表現出的字形是有差別的。
- 編碼後的字元:配置設定給字元的唯一數字編号
- 代碼空間:計劃用于字元代碼值的整數範圍
- 代碼寬度:每個字元代碼所用的位數
- 字元庫:特定的工作字元集
- 編碼後的字元集:組成字元庫的已經編碼的字元集,并為每個字元配置設定代碼空間中的一個代碼。
- 字元編碼方案:把數字化的字元代碼編碼為二進制碼的算法。
2.2 字元編碼方案
上面我們介紹了一些相關的術語,了解到其意思後。我們來看下一些常見的字元編碼方案。目前字元編碼方案主要有以下3種:
-
固定寬度
固定寬度方式的編碼用固定數量的比特表示每個編碼後的字元。這種方式處理速度較快,但是會浪費一些空間
-
可變寬度(無模态)
顧名思義,可變寬度就是根據字元代碼所需要的比特位,采用不同的寬度的比特進行存儲。這樣可以節約資源,而且還能根據需要利用多個位元組來表示不同的文字,比如中午就需要兩個位元組
-
可變寬度(有模态)
有模态的編碼使用特殊的“轉義”模式在不同的模态之間切換(這個我也沒有太了解其含義)。
常見編碼示例:
-
8位固定寬度
位固定寬度恒等編碼把每個字元代碼編碼為相應的 8 位二進制值。它隻能支援有 256 個字元代碼範圍的字元集。iso-8859 字元集家族系列使用的就是 8 位恒等編碼。
-
UTF-8
這個應該是目前比較流行的一種通用編碼了,能夠處理很多語言。是一種無模态的可變寬度編碼。第一位元組的高位表示編碼後的字元所用的位元組數,所需的每個後續位元組都含有 6 位的代碼 值,其編碼方式可以和ASCII編碼相容。如下表:
字元代碼的二進制位 | 位元組 1 | 位元組 2 | 位元組 3 | 位元組 4 | 位元組 5 | 位元組 6 |
---|---|---|---|---|---|---|
0-7 | 0ccccccc | - | - | - | - | - |
8-11 | 110ccccc | 10cccccc | - | - | - | - |
12-16 | 1110cccc | 10cccccc | 10cccccc | - | - | - |
17-21 | 11110ccc | 10cccccc | 10cccccc | 10cccccc | - | - |
22-26 | 111110cc | 10cccccc | 10cccccc | 10cccccc | 10cccccc | - |
27-31 | 1111110c | 10cccccc | 10cccccc | 10cccccc | 10cccccc | 10cccccc |
3 語言标記與HTTP
語言标記是命名口語的标準化字元串短語。同時,我們需要對這個标記的字元串進行标準化,否者每個人都有自己的命名習慣,字元串格式都不一樣,就無法從标記中提取出語言資訊。
3.1 Content-Language和Accept-Language首部
實體的 Content-Language 首部字段描述實體的目标閱聽人語言,其不限于文本文檔。音頻片段、電影以及應用程式都有可能是面向特定語言閱聽人的。任何面向特定語言閱聽人的媒體類型都可以有 Content-Language 首部。同時我們也可以在該首部指定多個語言,如:
Content-Language: en, fr
。
相對應的,用戶端也可以通過Accept-Language告知服務端我們能夠接受的語言種類。其優先順序從左至右
3.2 語言标記的類型
在 RFC 3066,“Tags for the Identification of Languages”(辨別語言的标記)中記錄了語言标記的标準化文法。可以用語言标記來表示:
- 一般的語言分類(比如 es 代表西班牙語);
- 特定國家的語言(比如 en-GB 代表英國英語);
- 語言的方言(比如 no-bok 指挪威的書面語);
- 地區性的語言(比如 sgn-US-MA 代表美國馬撒葡萄園島上的手語);
- 标準化的非變種語言(比如 i-navajo);
- 非标準的語言(比如 x-snowboarder-slang)。
标記一般由一個或多個部分組成,中間由"-"分隔,示例如下:

其中:
- 第一個标記是稱為主子标記,其值是标準化的
- 第二個子标記是可選,遵循它自己的命名規則
- 其他尾随的子标記是未注冊的
第一子标記和第二子标記都是有專門的文檔及相關組織專門維護和命名的,後面會介紹一些。其他的那些沒有專門維護的,一般需要在IANA進行注冊。這裡所有的标記都是不區分大小寫的。我們在解析的時候應該注意這點。
3.2.1 第一個子标記
第一個子标記通常是标準化的語言記号,選自 ISO 639 中的語言标準集合。不過也可以用字母 i 來辨別在 IANA 中注冊的名字,或用 x 表示私有的或者擴充的名字。其規則如下:
- 如果隻有2個字元,那就是來自 ISO 639 和 639-1 标準的語言代碼,如ar, en等
- 有3個字元,那就是來自 ISO 639-210 标準及其擴充的語言代碼,如ara,eng等
- 字母i,該語言标記是在 IANA 顯式注冊的
- 字母 x,該語言标記是私有的、非标準的,或擴充的子标記。
關于ISO639,ISO639-2等文檔這裡就不詳細介紹了,有興趣的自己搜尋來看看就清楚了。
3.2.2 第二個子标記
第二個子标記通常是标準化的國家記号,選自 ISO 3166 中的國家代碼和地區标準集合。不過也可以是在 IANA 注冊過的其他字元串,其規則如下:
- 2 個字元,那就是 ISO 316611 中定義的國家 / 地區;如:CN,FR
- 3~8 個字元,可能是在 IANA 中注冊的值;
- 單個字元,這是非法的情況。
4 國際化URI
本小節感覺了解的内容居多,是以這裡就沒有詳細記錄了。一般知道下面幾點即可:
- URI允許使用ASCII字元集的子集
- URI字元被分為轉義、保留和未保留三種,具體如下表所示:
字元類别 | 字元清單 |
---|---|
未保留 | [A-Za-z0-9] |
保留 | “;” |
轉義 | “%” <HEX> <HEX> |