前端學HTTP之字符集

前面的話

  HTTP報文中能夠承載以任何語言表示的內容,就像它能承載圖像、影片或任何類型的媒體那樣。對HTTP來講,實體主體只是二進制信息的容器而已。爲了支持國際性內容,服務器須要告知客戶端每一個文檔的字母表和語言,這樣客戶端才能正確地把文檔中的信息解包爲字符並把內容呈現給用戶,而要實現這個功能,須要用到接下來要詳細介紹的字符集html

 

首部概述

  服務器經過HTTP協議的Content-Type首部中的charset參數和Content-Language首部告知客戶端文檔的字母表和語言。這些首部描述了實體主體的「信息盒子」裏面裝的是什麼,如何把內容轉換成合適的字符以便顯示在屏幕上以及裏面的詞語表示的是哪一種語言算法

  同時,客戶端須要告知服務器用戶理解何種語言,瀏覽器上安裝了何種字母表編碼算法。客戶端發送Accept-Charset首部和Accept-Language首部,告知服務器它理解哪些字符集編碼算法和語言以及其中的優先順序數組

  下面的HTTP報文中的這些Accept首部多是母語爲法語的人發出的。他喜歡使用母語,但也會說一點兒英語,他的瀏覽器支持iso-8859-1 西歐字符集編碼和UTF-8 Unicode字符集編碼瀏覽器

Accept-Language: fr, en;q=0.8 
Accept-Charset: iso-8859-l, utf-8

  參數「q=0.8」是質量因子(quality factor),說明英語的優先級(0.8)比法語低(默認值是1.0)安全

 

編碼過程

  HTTP字符集的值說明如何把實體內容的二進制碼轉換爲特定字母表中的字符。每一個字符集標記都命名了一種把二進制碼轉換爲字符的算法(反之亦然)。字符集標記在由IANA維護的MIME字符集註冊機構進行了標準化。附錄H中概述了其中的不少字符集服務器

  下面的Content-Type首部告知接收者,傳輸的內容是一份HTML文件,用charset參數告知接收者使用iso-8859-6阿拉伯字符集的解碼算法把內容中的二進制碼轉換爲字符:字體

Content-Type: text/html; charset=iso-8859-6

  iso-8859-6的編碼算法把8位值域映射爲拉丁字母和阿拉伯字母,以及數字,標點和其餘符號。例如,在下圖中,突出顯示的二進制碼的值是225,它在iso-8859-6中被映射到阿拉伯字母「FEH」(讀音相似英語字母F)網站

  [注意]與漢語、日語不一樣的是,阿拉伯語中只有28個字符,8位空間有256個不一樣的值,足以容納拉丁字符、 阿拉伯字符以及其餘符號編碼

  有些字符編碼(好比UTF-8和iso-2022-jp)更加複雜,它們是可變長(variable-length)編碼,也就是說每一個字符的位數都是可變的。這種類型的編碼容許使用額外的二進制位表示擁有大量字符的字母表(好比漢語和日語),僅用較少的二進制位來表示標準的拉丁字符spa

  咱們想把文檔中的二進制碼轉換爲字符以便顯示在屏幕上。但因爲有不少不一樣的字母表,也有不少不一樣的方法把字符編碼成二進制碼(這些方法各有優缺點),咱們須要一種標準方法來描述並應用把二進制碼轉換爲字符的解碼算法

  把二進制碼轉換爲字符要通過兩個步驟,以下圖所示

 

  在圖a中,文檔中的二進制碼被轉換成字符代碼,它表示了特定編碼字符集 中某個特定編號的字符。在這個例子裏,解碼後的字符代碼是數字編號225

  在圖b中,字符代碼用於從編碼的字符集中選擇特定的元素。在iso-8859-6中,值225對應阿拉伯字母「FEH」。在步驟a和b中使用的算法取決於MIME的charset標記

  國際化字符系統的關鍵目標是把語義(字母)和表示(圖形化的顯示形式)隔離開來。HTTP只關心字符數據和相關語言及字符集標籤的傳輸。字符形狀的顯示是由用戶的圖形顯示軟件(包括瀏覽器、操做系統、字體等)完成的,如圖c所示

  若是客戶端使用了錯誤的字符集參數,客戶端就會顯示一些奇怪的錯亂字符。假設瀏覽器從主體中得到值225(二進制爲11100001)

  若是瀏覽器認爲主體是用iso-8859-1西歐字符編碼的,它將會顯示帶有重音符號的小寫拉丁字母「a」

  若是瀏覽器使用iso-8859-6阿拉伯編碼,它將會顯示阿拉伯字母「FEH」

  若是瀏覽器使用iso-8859-7希臘編碼,它將會顯示小寫的希臘字母「Alpha」

  若是瀏覽器使用iso-8859-8希伯來編碼,它將會顯示希伯來字母「BET」

【標準化的MIME charset值】

  特定的字符編碼方案和特定的已編碼字符集組合成一個MIME字符集(MIME charset)。HTTP在Content-Type和Accept-Charset首部中使用標準化的MIME charset標記。MIME charset的值都會在IANA註冊

  下表列出了文檔和瀏覽器所使用的一些MIME charset編碼方案

  [注意]關於完整的已註冊字符集內容請移步至此

  Web服務器經過在Content-Type首部中使用charset參數把MIME字符集標記發送給客戶端

Content-Type:text/html; charset=iso-2022-jp

  若是沒有顯式地列出字符集,接收方可能就要設法從文檔內容中推斷出字符集。對於HTML內容來講,能夠在描述charset的<meta HTTP-EQUIT="Content-Type">標記中找到字符集

  下例中展現了HTML META標記如何把字符集設置爲日語編碼iso-2022-jp。若是文檔不是HTML類型,或其中沒有META Content-Type標記,軟件能夠設法掃描實際的文本,看看可否找出語言和編碼的常見模式,以此推斷字符編碼

<head>
<meta HTTP-EQUIT="Content-Type" content="text/html;charset=iso-2202-jp">
<meta lang="jp">
<title>Japanese</title>
</head>

  在過去的幾十年間,人們開發了成千上萬種字符編解碼方法。大多數客戶端不可能支持全部這些不一樣的字符編碼和映射系統

  HTTP客戶端可使用Accept-Charset請求首部來明確告知服務器它支持哪些字符系統。Accept-Charset首部的值列出了客戶端支持的字符編碼方案。例如,下面的HTTP請求首部代表,客戶端接受西歐字符系統iso-8859-1和UTF-8變長的Unicode兼容系統。服務器能夠隨便選擇這兩種字符編碼方案之一來返回內容

Accept-Charset: iso-8859-1, utf-8

  [注意]沒有Content-Charset這樣的響應首部和Accept-Charset請求首部匹配。爲了和MIME標準兼容,響應的字符集是由服務器經過Content-Type響應首部的charset參數帶回來的。不對稱真是太糟了,不過須要的信息卻是都有了

 

編碼語法

【術語】

  如下是應當瞭解的電子化字符系統的8個術語

  一、字符

  字符是指字母、數字、標點、表意文字(好比漢語)、符號,或其餘文本形式的書寫「原子」。由統一字符集(Universal Character Set, UCS,它的非正式的名字是Unicode3)獨創,爲多種語言中的不少字符開發了一系列標準化的文本名稱,它們經常使用來便捷地命名字符,並且不會與其餘字符衝突

  二、字形

  描述字符的筆畫圖案或惟一的圖形化形狀。若是一個字符有多種不一樣的寫法,就有多個字形

  三、編碼後的字符

  分配給字符的惟一數字編號,這樣咱們就能夠操做它了

  四、代碼空間

  計劃用於字符代碼值的整數範圍

  五、代碼寬度

  每一個固定大小的字符代碼所用的位數

  六、字符庫

  特定的工做字符集,至關於全體字符的一個子集

  七、編碼後的字符集

  組成字符庫(從全球的字符中選出若干字符)的已編碼字符集,併爲每一個字符分配代碼空間中的一個代碼。換句話說,它把數字化的字符代碼映射爲實際的字符

  八、字符編碼方案

  把數字化的字符代碼編碼成一系列二進制碼(並能相應地反向解碼)的算法。字符編碼方案可用來減小識別字符所須要的數據總量(壓縮)、解決傳輸限制、統一重疊編碼字符集

【糟糕的命名】

  從技術上說,MIME中的charset標記(用在Content-Type首部的charset參數中和Accept-Charset首部中)描述的壓根就不是字符集。MIME中的charset值所命名的是把數據位映射爲惟一的字符的一整套算法。它是字符編碼方案(character encoding scheme)和編碼後的字符集(coded character set)這兩種概念的組合

  由於關於字符編碼方案和編碼後的字符集方面的標準都已經發布過了,因此,這個術語的使用是很草率的,很容易引發混淆。下面是HTTP/1.1的做者們對於他們如何使用這些術語的介紹

  術語「字符集」在本文檔中是指一種方法,它能夠把一系列8位字節轉換爲一系列字符。注意:術語「字符集」常常被稱爲「字符編碼」。但因爲HTTP和MIME共享一樣的註冊信息,術語也能共享是很重要的

  IETF在RFC 2277中也採用了非標準的術語:

  本文檔中使用術語「字符集」來表示一組把一系列8位字節轉換爲一系列字符的規則的集合,好比編碼後的字符集與字符編碼方案的組合。這與MIME的「charset=」參數中標識符的用法相同,而且已在IANA的字符集註冊表中註冊。(注意這不是在其餘標準主體,好比在國際標準化組織ISO中使用的術語)

  [注意]更糟糕的是,MIME中的charset標記常常會從特定的編碼後字符集的名稱或編碼方案的名稱裏面選取。例如,iso-8859-1是一個編碼後字符集(它爲一個包含256個歐洲字符的集合分配了數字化的代碼),但MIME用charset值iso-8859-1來表示一種8位的、對編碼後的字符集恆等的編碼。這種不精確的術語並非致命的問題,但在閱讀標準文檔的時候,須要對其假設用法保持清醒的頭腦

  所以,在閱讀標準文檔的時候,要保持清醒,這樣才能確切地知道它所定義的究竟是什麼

【字符】

  字符是書寫的最基本的構建單元。字符能夠表示字母、數字、標點、表意符號(好比在漢語中)、數學符號,或其餘書寫的基本單元

  字符和字體以及風格無關。下圖顯示了同一個字符(UCS中的命名是LATIN SMALL LETTER A)的若干變體。儘管它們的筆畫圖案和風格有很大的不一樣,但母語是西歐語言的讀者都能馬上辨認出這5個形狀是同一個字符

  在不少書面語體系中,根據一個字符在單詞中位置的不一樣,同一個字符也會有不一樣的筆畫形狀。例如,下圖中的4種筆畫都表示字符ARABIC LETTER AIN

  圖a顯示了AIN做爲一個單獨的字符時是如何書寫的。圖d顯示的是AIN在單詞開頭時的情形。圖c顯示了AIN在單詞中間的情形,而圖b顯示的是AIN在單詞結尾處的情形

【字形】

  不要把字符和字形混淆。字符是惟一的、抽象的語言「原子」。字形是畫出每一個字符時使用的特定方式。根據藝術形式和手法的不一樣,每一個字符能夠有不少不一樣的字形

  一樣,也不要把字符與表示形式混淆起來。爲了讓書法做品更好看,不少手寫體和字體容許人們把相鄰的字符漂亮地連寫起來,稱爲連筆(ligatures),這樣兩個字符就平滑地鏈接在一塊兒了。母語爲英語的做者常把F和I結合爲FI連筆,而阿拉伯語的做者常把字符「LAM」和「ALIF」結合爲一種很優雅的連筆

  這裏給出通常的規則:若是用一種字形替代另外一種的時候,文本的意思變了,那這些字形就是不一樣的字符。不然,它們就是同一個字符的不一樣風格的表示形式

【編碼後的字符集】

  根據RFC 2277和2130的定義,編碼後的字符集把整數映射到字符。編碼後的字符集常常用數組來實現,經過代碼數值來索引。數組的元素就是字符

  下面咱們來看一些重要的編碼後的字符集標準,包括具備歷史意義的US-ASCII字符集、ASCII的iso-8859擴展、日文的JIS X 0201字符集以及統一字符集(Universal Character Set, Unicode)

  一、US-ASCII:全部字符集的始祖

  ASCII是最著名的編碼後字符集,早在1968年就由ANSI在標準X3.4,「美國標準信息交換代碼」(American Standard Code for Information Interchange)中進行了標準化。ASCII的代碼值只是從0到127,所以只須要7個二進制碼就能夠覆蓋代碼空間。ASCII的推薦名稱是US-ASCU,這樣能夠和那些7位字符集的一些國際化變體區分開來。HTTP報文(首部,URI等)使用的字符集是US-ASCII

  二、iso-8859

  iso-8859字符集標準是US-ASCII的8位超集,使用二進制碼的高位增長了一些國際化書面字符。由額外的二進制碼提供的附加空間(多了128個代碼)還不夠大,甚至都不夠全部的歐洲字符使用,更不用說亞洲字符了。所以iso-8859爲不一樣地區定製了不一樣的字符集,以下所示

iso-8859-1    西歐語言(例如,英語、法語)
iso-8859-2    中歐和東歐語言(例如,捷克、波蘭)
iso-8859-3    南歐語言
iso-8859-4    北歐語言(例如,拉托維亞,立陶宛,格陵蘭}
iso-8859-5    斯拉夫語(例如,保加利亞、俄羅斯、塞爾維亞)
iso-8859-6    阿拉伯語
iso-8859-7    希臘語
iso-8859-8    希伯來語
iso-8859-9    土耳其語
iso-8859-10   日耳曼和斯堪的納維亞語言(例如,冰島、因紐特)
iso-8859-15   對iso-8859-1的修改,包括了新的歐元字符

  iso-8859-1也稱爲Latin1,是HTML的默認字符集。能夠用它來表示大多數西歐語言的文本。由於iso-8859-15中包含了新的歐元符號,有過一些用它來代替iso-8859-1並做爲HTTP默認編碼後字符集的討論。然而,因爲iso-8859-1已經被普遍採用,要大範圍地變動到iso-8859-15恐怕不是短期內能夠完成的

  三、JIS X 0201

  JIS X 0201是把ASCII擴展到日文半寬片假名字符的一個極小化的字符集。半寬片假名字符最先用在日文電報系統中。JISX 0201經常被稱做JIS Roman,JIS是 「Japanese Industrial Standard」(日文工業化標準)的縮寫

  四、JIS X 0208與JIS X 0212

  日文中包括數千個來自幾個書面語系統中的字符。儘管能夠勉強只使用JIS X 0201中的那63個基本的片假名字符,但實際使用中須要遠比這個更完整的字符集

  JIS X 0208字符集是首個多字節日文字符集,它定義了6879個編碼的字符,其中大多數是來源於中文的日本漢字。JIS X 0212字符集又擴充了6067個字符

  五、UCS

  UCS(Universal Character Set,統一字符集)是把全世界的全部字符整合到單一的編碼後字符集的環球標準化成果。UCS由ISO 10646定義。Unicode是遵循UCS標準的商業化聯合組織。UCS具備能容納百萬以上字符的代碼空間,不過基本集合只有大約5萬個字符

【字符編碼方案】

  字符編碼方案規定如何把字符的代碼數字打包裝入內容比特,以及在另外一端如何將其解包回字符代碼

  字符編碼方案有如下3種主要類型

  一、固定寬度

  固定寬度方式的編碼用固定數量的比特表示每一個編碼後的字符。它們能被快速處理,但可能會浪費空間

  二、可變寬度(無模態)

  可變寬度方式的編碼對不一樣的字符代碼數字採用不一樣數量的比特。對於經常使用字符,這樣能夠減小須要的位數,並且還能在容許使用多字節來表示國際性字符的同時,保持對傳統8位字符集的兼容性

  三、可變寬度(有模態)

  有模態的編碼使用特殊的「轉義」模式在不一樣的模態之間切換。例如,能夠用有模態的編碼在文本中使用多個互相有重疊的字符集。有模態的編碼處理起來比較複雜,但它們能夠有效地支持複雜的書寫系統

  下面咱們來看一些常見的編碼方案

  一、8位

  8位固定寬度恆等編碼把每一個字符代碼編碼爲相應的8位二進制值。它只能支持有256個字符代碼範圍的字符集。iso-8859字符集家族系列使用的就是8位恆等編碼

  二、UTF-8

  UTF-8是一種流行的爲UCS設計的字符編碼方案,UTF表示UCS變換格式(UCS Transformation Format)。UTF-8爲字符代碼值使用的是無模態的變寬編碼,第一字節的高位表示編碼後的字符所用的字節數,所需的每一個後續字節都含有6位的代碼值

  若是編碼後的第1字節的最高位是0,長度就是1字節,剩餘的7位就包含字符的代碼。這樣帶來的美妙結果就是和ASCII兼容(但和iso-8859系列不兼容,由於iso-8859系列使用了最高位)

  例如,字符代碼90(ASCII的「Z」)會被編碼爲1個字節(01011010),而代碼5073(13位二進制值爲1001111010001)會被編碼爲3個字節:11100001 10001111 10010001

  三、iso-2022-jp

  iso-2022-jp是互聯網上的日文文檔中普遍使用的編碼。它是變寬、有模態的,全部值都不超過128,以免和不支持8位字符的軟件出現兼容性問題

  編碼上下文始終被設置爲4種預設的字符集之一,使用特殊的「轉義序列」 (escape sequence)在字符集之間切換。iso-2022-jp的初始狀態使用US-ASCII字符集,使用3個字節的轉義序列能夠切換到JIS X 0201(JIS-Roman)字符集或大得多的JIS X 0208-1978和JIS X 0208-1983字符集

  下表中列出了這些轉義序列。實際上,日文文本以ESC $ @或ESC $ B 開始,以ESC(B或ESC(J結束

  在US-ASCII或JIS-Roman模態下,每一個字符使用單個字節。當使用更大的JISX 0208系列的字符集時,每一個字符代碼使用2個字節。該編碼把發送的字節的值域範圍限制在33~126之間

  四、euc-jp

  euc-jp是另外一種流行的日文編碼。EUC表明「Extended Unix Code」(擴展Unix代碼),最先是爲了在Unix操做系統上支持亞洲字符而開發的

  和iso-2022-jp相似,euc-jp編碼也是變長的,容許使用幾種標準的日文字符集。但和iso-2022-jp不一樣的是,euc-jp編碼不是模態的。沒有轉義序列能夠在不一樣模態之間切換

  euc-jp支持4種編碼後的字符集:JIS X 0201(JIS-Roman,對ASCII進行一些日文替換)、JIS X 020八、半寬片假名(最先在日文電報系統中使用的63個字符)以及JIS X 0212

  編碼JIS Roman(它和ASCII兼容)的時候使用1個字節,對JIS X 0208和半寬片假名則使用2個字節,而對JIS X 0212使用3個字節。這種編碼有點浪費空間但處理起來很簡單

  下表歸納了此編碼的格局

語言標記

  語言標記是命名口語的標準化字符串短語

  名字須要標準化,否則的話,有些人會把法語文檔打上French標記,而有些其餘人會用Francis,還有些人可能會用France,更有些懶人可能會用Fra甚至是F。標準化語言標記就能夠避免這些混亂

  英語的標記是en,德語的標記是de,韓語的標記是ko,等等。語言標記可以描述語言的地區變種和方言,好比巴西葡萄牙語的標記是pt-BR、美式英語的標記是en-US,漢語中的湖南話的標記是zh-xiang。甚至還有個標準語言標記i-klingon是描述克林根語的

  實體的Content-Language首部字段描述實體的目標受衆語言。若是內容主要是給法語受衆的,其Content-Language首部字段就將包含:

Content-Language:fr

  Content-Language首部不只限於文本文檔。音頻片斷、電影以及應用程序都有多是面向特定語言受衆的。任何面向特定語言受衆的媒體類型均可以有Content-Language首部。在下圖中,音頻文件標記爲面向納瓦霍(Navajo)聽衆

  若是內容是面向多種語言受衆的,能夠列出多種語言。就像在HTTP規範中建議的,一份同時用英語和毛利語寫的「Treaty of Waitangi」(懷唐伊條約)譯稿,能夠這樣描述:

Content-Language:mi, en

  不過,不能僅根據有多種語言在實體中出現就認爲它是面向多種語言受衆的。爲初學者編寫的語言入門教材,好比「A First Lesson in Latin」(拉丁語第一課),顯然是爲英語受衆準備的,應當只用en來描述

  咱們絕大多數人至少懂一種語言。HTTP容許咱們把語言方面的限制和優先選擇都發送給網站服務器。若是網站服務器有以多種語言表示的資源版本,它就能把內容用咱們最優選的語言表示出來

  客戶端請求西班牙語內容:

Accept-Language:es

  能夠在Accept-Language首部中放入多個語言標記以枚舉所支持的所有語言及其優先順序(從左到右)。客戶端首選英語,但也接受瑞士德語(標準語言標記是de-CH)或其餘德語變種(標記是de):

Accept-Language:en, de-CH, de

  客戶端使用Accept-Language首部和Accept-Charset首部請求能夠理解的內 容

  在RFC 3066,「Tags for the Identification of Languages」(標識語言的標記)中記錄了語言標記的標準化語法。能夠用語言標記來表示:通常的語言分類(好比es表明西班牙語);特定國家的語言(好比en-GB表明英國英語);語言的方言(好比no-bok指挪威的書面語);地區性的語言(好比sgn-US-MA表明美國馬撒葡萄園島上的手語);標準化的非變種語言(好比i-navajo);非標準的語言(好比 x-snowboarder-slang)

  語言標記有一個或多個部分,用連字號分隔,稱爲子標記:

  第一個子標記稱爲主子標記,其值是標準化的;第二個子標記是可選的,遵循它本身的命名標準;其餘尾隨的子標記都是未註冊的

  主子標記中只能含有字母(A-Z)。其後的子標記能夠含有字母和數字,長度最多8個字符

  下圖中給出了一個示例

  全部的標記都是不區分大小寫的,也就是說,標記en和eN是等價的。可是,習慣上用全小寫來表示通常的語言,而用全大寫來表示特定的國家。例如,fr表示全部分類爲法語的語言,而FR表示國家法國

  第一個和第二個語言子標記的值由各類標準文檔以及相關的維護組織定義。IANA依據RFC 3066中歸納的規則來管理標準的語言標記列表

  若是語言標記由標準的國家和語言值組成,標記就不須要專門註冊。只有那些沒法用標準的國家和語言值構成的語言標記才須要專門向IANA註冊

  第一個子標記一般是標準化的語言記號,選自ISO 639中的語言標準集合。不過也能夠用字母i來標識在IANA中註冊的名字,或用x表示私有的或者擴展的名字,下面是各類規則

  若是第一個子標記含有2個字符,那就是來自ISO 639和639-1標準的語言代碼;若是含有3個字符,那就是來自ISO 639-223標準及其擴展的語言代碼;若是是字母i,則表示該語言標記是在IANA顯式註冊的;若是是字母x,則表示該語言標記是私有的、非標準的,或擴展的子標記

  下表中給出了一些示例

  第二個子標記一般是標準化的國家記號,選自ISO 3166中的國家代碼和地區標準集合。不過也能夠是在IANA註冊過的其餘字符串,下面是各類規則。
若是第二個子標記含有2個字符,那就是ISO 3166中定義的國家/地區;若是含有3-8個字符,多是在IANA中註冊的值;若是是單個字符,這是非法的狀況

  下表中列出了ISO 3166中的部分國家代碼

  除了最長能夠到8個字符(字母和數字)以外,第三個和其後的子標記沒有特殊規則

 

國際化URI

  直到今天,URI尚未爲國際化提供足夠的支持。除了少數(定義得很糟的)例外,URI現在仍是由US-ASCII字符的一個子集組成的。人們正在努力使主機名和URL的路徑中能包含更豐富的集合中的字符,但直到如今,這些標準尚未被普遍接受和部署

  URI的設計者們但願世界上每一個人都能經過電子郵件、電話、公告板,甚至無線電來共享URI。他們還但願URI容易使用和記憶,但這兩個目標是相互衝突的

  爲了讓世界各地的人們都可以便捷地輸入、操控,以及共享URI,設計者們爲URI選擇了經常使用字符的一個頗有限的子集(基本的拉丁字母表中的字母、數字以及少數特殊符號)。世界上絕大多數軟件和鍵盤都支持這個小的字符集合

  但不幸的是,限制了字符集的話,URI就沒法被全球的人們方便地使用和記憶。世界上有很大一部分人甚至都不認識拉丁字母,他們幾乎沒法把URI看成抽象模式來記憶

  URI的設計者們以爲確保資源標識符的可轉抄能力(transcribability)和共享能力比讓它們由最有意義的字符組成更加劇要。所以,現在的URI基本上是由ASCII字符的受限子集構成的

  URI中容許出現的US-ASCII字符的子集,能夠被分紅保留、未保留以及轉義字符這幾類。未保留的字符可用於URI容許其出現的任何部分。保留的字符在不少URI中都有特殊的含義,所以通常來講不能使用它們

  下表中列出了所有未保留、保留,以及轉義字符

【轉義】

  URI轉義提供了一種安全的方式,能夠在URI內部插入保留字符以及本來不支持的字符(好比各類空白)。每一個轉義是一組3字符序列,由百分號(%)後面跟上兩個十六進制數字的字符。這兩個十六進制數字就表示一個US-ASCII字符的代碼

  例如,要在URL中插入一個空白(ASCII 32),能夠用轉義%20,由於20是32的十六進制表示。相似地,若是想插入一個百分號而且不想讓它被看成轉義,就能夠輸入%25,25是百分號的ASCII代碼的十六進制值

  下圖展現了URI中的概念性字符是如何轉換爲當前字符集中字符的代碼字節的。須要處理URI時,轉義會被反轉義回來,產生它們表明的ASCII代碼的字節

  在內部處理時,HTTP應用程序應當在傳輸和轉發URI的時候保持轉義不變。HTTP應用程序應該僅在須要數據的時候纔對URI進行轉義。更重要的是,應用程序應該確保任何URI都不會被反轉義2次,由於在轉義的時候可能會把百分號編碼進去,反轉義出來以後,再轉一次就會致使數據丟失

  須要注意的是,要轉義的值自己應該在US-ASCII代碼值的範圍內(0~127)。某些應用程序試圖用轉義值來表示iso-8859-l中擴展的字符(代碼範圍在128-
255)。例如,網站服務器可能會錯誤地用轉義來對包含了國際字符的文件名進行編碼。這樣作是不對的,可能會使別的應用出問題

  例如,文件名Sven Olssen.html(包含了一個元音變音)可能被網站服務器編碼爲 Sven%20%D6lssen.html。把空格編碼爲%20是對的,但從技術上說,把O編碼爲%D6是非法的,由於代碼D6(十進制值214)落在了ASCII代碼範圍以外。ASCII只定義了最大值爲0X7F(十進制值127)的代碼

【模態切換】

  有些URI也用ASCII字符的序列來表示其餘字符集中的字符。例如,可能使用iso-2022-jp編碼插入「ESC(J」,切換到JIS-Roman字符集,用「ESC(B」切換回ASCII字符集。這在一些本地化的環境中能夠工做,但這種方式沒有進行良好的定義,並且沒有標準化的方案來識別URL所使用的特定編碼。正如RFC 2396的做者所說的那樣:

  對於含有非ASCII字符的原始字符序列來講,境況複雜。若是可能用到多個字符集的活,傳輸表示字符序列的8位字節序列的因特網協議期待能有辦法來識別所用的字符集[RFC 2277]

  然而,在通用的URI語法中沒有提供進行這種識別的手段。個別的URI方案能夠請求單一的字符集,定義默認的字符集,或提供指示所用字符集的方法。期待未來對這個規範的修改能爲URI中的字符編碼提供一種系統化的處理方案

  目前,URI對國際化應用還不是很是友好。URI的可移植性目標比語言靈活性方面的目標更重要。人們正在盡最大努力使URI更加國際化,但在短時間內,HTTP應用程序仍是應當堅持使用ASCII。它從1968年就出現了,因此只用它的話,一切還不至於太糟

 

注意事項

  HTTP首部必須由US-ASCII字符集中的字符構成。不過,並非全部的客戶端和服務器都正確地實現了這一點,可能會時不時收到一些代碼值大於127的非法字符

  不少HTTP應用程序使用操做系統和庫例程來處理字符(好比Unix中的字符分類庫ctype),但不是全部這些庫都支持ASCII範圍(0-127)以外的字符代碼

  在某些狀況下(通常來講,是較老的實現),當輸入非ASCII字符時,這些庫可能會返回不正確的結果,或者使應用程序崩潰。假設報文中含有非法數據,在使用這些字符分類庫來處理HTTP報文以前,要仔細閱讀它們的文檔

  HTTP的規範中明肯定義了合法的GMT日期格式,但要知道並不是全部Web服務器和客戶端都遵照這些規則。例如,咱們曾見過Web服務器發送的無效HTTP Date(日期)首部中的月份是用本地語言表示的

  HTTP應用程序應當嘗試容忍一些不合規矩的日期,不能在接收的時候崩潰。不過也不是全部發送出來的日期都能被正確解釋,若是日期沒法解析,服務器應當謹慎處理

  DNS目前還不支持在域名中使用國際化的字符。如今正在進行支持多語言的域名的相關標準化工做,但尚未被普遍部署

相關文章
相關標籤/搜索