Web編碼總結(jié)

2018-06-16 17:31 更新

今天遇到了一個奇怪的問題,兩次ajax發(fā)送的同一個變量值,后端接收到的編碼不一樣……,一時間,我竟然發(fā)現(xiàn)自己對于編碼的問題不能說的很清楚。

lisp主張代碼即數(shù)據(jù),其實我們寫的代碼也是數(shù)據(jù)(信息),數(shù)據(jù)的存儲和傳播都要就要涉及到編碼的問題。就像我們向?qū)Ψ絺鬟f信息之前,先要問對方:can you spreak in english。

小貼士:嗨,你知道嗎!windows的換行符是 \r\l,linux的是 \l,mac的是 \r,這是有意還是故意的呢……

本文會試圖說清web開發(fā)過程中,如下方面的編碼問題:

  • 編碼簡史
  • 文件編碼
  • HTML編碼
  • CSS編碼
  • JavaScript編碼
  • ajax編碼

編碼簡史

如果想把編碼問題說清楚,那恐怕你看到這里就會把頁面關掉了,所以這里僅簡要介紹下國內(nèi)web開發(fā)中常用的一些編碼。如果你了解或不感興趣,可以直接跳過本部分。

  • ASCII/EASCII(ISO/IEC 646)
  • GB2312/GBK/GB18030
  • Unicode/UTF8/UTF16

進入數(shù)字時代,整個世界都要數(shù)字化,最先數(shù)字化的就是文字,老外的自我中心論,以為世上僅有abcd…… 26個字母,便發(fā)明了ASCII(美國標準信息交換碼)。

ASCII 使用一個字節(jié)的低7位的不同組合來表示字母數(shù)字和一些其他字符,2^7 = 1287位二進制共可以代表128個字母。

后來為了表示更多的字符便將ASCII擴展為8位,稱為EASCII,并等同于國際標準ISO/IEC 646

而我們?yōu)榱俗対h語也能數(shù)字化,變發(fā)明了gb2312,gb2312使用兩個字節(jié)16位表示漢字,為了兼容ASCII將每個字節(jié)的高8位置為1,共有14位可用,2^14 = 16384,但GB 2312標準共收錄6763個漢字,后來發(fā)現(xiàn)不太夠用,又擴展了gbk,gb18030。

終于老外發(fā)明了 Unicode,一切都解決了,Unicode有兩個字節(jié)的16位的編碼空間,Unicode是一個歸法,比較常用的有UTF8和UTF16兩種編碼方式。

UTF8在web領域比較常用,是一種變長的編碼方式,UTF16是一種定長方式。

最后來看一下,‘回’字的不同編碼,要記住哦,后面會多次用到。

文件編碼

文件編碼也可以說是存儲的編碼。

我們寫的代碼,最終會以二進制的方式,持久化到計算機的存儲設備中。

不同編碼的文件,會以不同的規(guī)則存儲到磁盤中,不同的編碼要有自己獨特的規(guī)則,這樣才能在讀取的時候不發(fā)生沖突,也就是要能識別出來自己,計算機在打開文件的時候都是靠猜測來解碼的。

如果存儲的編碼(算法)和打開的編碼(算法)不一致,就會出現(xiàn)亂碼的情況。

文件在網(wǎng)絡上傳入要聲明自己的編碼,我們一定要清楚源文件的編碼,然后才能進行后序工作。

對于前端而言會涉及html,css和js源文件的編碼,而國內(nèi)常用的編碼如下:

  • ascii
  • gbk
  • utf-8

推薦大家用utf-8,不容易出問題,但由于歷史原因,國內(nèi)有很多網(wǎng)站的編碼都是gbk,下面是BAT的網(wǎng)站情況:

  • qq.com gb2312
  • taobao.com gbk
  • baidu utf-8

百度歷史比較悠久的產(chǎn)品線的編碼也是gbk,比如百度知道。

HTML

網(wǎng)頁中HTML的編碼由哪些部分決定呢?真正運行在服務器上的HTML編碼由下面幾部分決定

  • HTTP頭
  • meta
  • user-agent

上面給出的三個因素的權(quán)重是由高到低,也就是說HTTP頭會覆蓋meta的信息。

如果你還不知道什么是HTTP頭那么請自行百度,HTTP頭中的編碼信息如下圖中紅色方塊圈起來的部分,代表當前頁面的編碼是utf8。用戶代理收到這個信息后,就會用utf8編碼來將收到的字節(jié)流解碼。

有些服務器會設置文件的默認編碼信息,有些則不會,后端語言都可以自行設置頁面的html編碼,在php中設置http編碼代碼如下:

header("Content-Type:text/html; charset=utf-8");

如果沒有設置http頭信息,或者在文件系統(tǒng)直接打開頁面,html的meta標簽就派上了用場,meta中可以設置http頭信息,下面的代碼和上面php的功能相同:

<meta content="text/html; charset=utf-8" http-equiv="Content-Type">

在html5中將上面的代碼簡化為如下形式:

<meta charset="utf-8">

如果既沒有設置http頭,也沒有meta標簽,那么用戶代碼會使用系統(tǒng)的默認設置,windows下的中文環(huán)境的默認編碼一般是 gb2312,所以用戶代理就會用gb2312來解碼頁面,如果頁面的編碼也剛好是gb2312那么萬事ok,否則就會出現(xiàn)亂碼。

用戶代理一般可以設置默認的編碼是什么。比如chrome打開設置下的內(nèi)容網(wǎng)絡,會看到如下的設置界面。

注:如果最終顯示的編碼和頁面本身的編碼不同就會出現(xiàn)亂碼。

CSS

說完了HTML的編碼再來說說CSS的編碼,如果HTML文件和CSS文件的編碼不一致,那么就需要單獨聲明才可以。

在html4中l(wèi)ink有一個屬性——charset可以用來指定引入css文件的編碼,但這個屬性在html5中已經(jīng)廢棄了,雖然廢棄了但在瀏覽器中還是可以使用的,下面的代碼顯示指定css文件的編碼為gbk。

<link rel="stylesheet" href="gbk-1.css" charset="gbk">

然而html5廢棄了這個屬性那么該怎么辦呢,其實廢棄這個屬性,是因為把這個功能代理給了css文件,css中有一個@charset指定,可以指定頁面的編碼,將下面的代碼放在css文件的頂部,會顯示聲明頁面的編碼為utf8。

@charset utf-8

那么問題來了,如果即設置了charset屬性,又設置了@charset指定,結(jié)果是@charset指定會覆蓋link的charset屬性,charset屬性已經(jīng)廢棄了,建議用css的@charset指令。

注:如果我們顯示指定的編碼和css文件的編碼不一致也會導致亂碼問題。

JavaScript

說清了CSS的編碼,我們再來說JavaScript的編碼問題,首先還是如果HTML文件的編碼和JavaScript文件的編碼不一致的話就會產(chǎn)生亂碼,這時就需要我們顯示聲明一下js文件的編碼才可以。

html中的script標簽有一個charset屬性,用來指定引入外部jss文件的編碼(字符集)。下面的代碼顯示聲明引入的js的編碼是utf8。

<script src="***.js" charset="utf-8"></script>

注:如果我們顯示指定的編碼和js文件的編碼不一致也會導致亂碼問題。

其實在JavaScript中僅支持utf16編碼,其實也不是utf16,而是utf16的子集——ucs-2,這導致在js中無法表示BMP之外的文字(更多信息請看這里)。

無論js源文件的編碼是什么,下面的源代碼的輸出結(jié)果是一樣的——前提是解碼js的過程正確。

'回'.charCodeAt(0)#輸出 22238

22238的十六進制表示是56 DE,而這正是‘回’字的utf16編碼。

ajax

說ajax之前,先來說說表單提交吧,下面分別是utf8頁面和gbk頁面的表單提交請求,其中參數(shù)name是’回’字??梢钥闯霰韱握埱蟮木幋a是由頁面決定的。

http://localhost/github/webtest/charset/form.php?name=%E5%9B%9E
http://localhost/github/webtest/charset/form.php?name=%BB%D8

ajax發(fā)送的代碼也是由頁面決定的,但我們在發(fā)送參數(shù)前都會encodeURIComponent一下,encodeURIComponent不管頁面編碼是什么,都會返回utf8編碼。

讓我們構(gòu)造一個例子,頁面A的編碼為gbk,有如下的代碼:

xhr.open("GET","form.php?name=" + encodeURIComponent('回') + 'namegbk=' + '回',true);

我們看到發(fā)送的ajax請求如下所示:

http://localhost/github/webtest/charset/form.php?name=%E5%9B%9Enamegbk=%BB%D8

這個例子巧妙的驗證了上面的結(jié)論。

再來說說json,json只支持utf8編碼,所以不要返回gbk編碼的json。

總結(jié)

在信息交換的任何一個環(huán)節(jié),如果編碼信息和解碼信息不一致都會產(chǎn)生亂碼問題。

本文中的所有例子都可以從webtest下載。

關于編碼還有很多東西可以需要學習,我強烈建議你可以閱讀下參考資料里面的一些文章,同時我還建議您閱讀”code“這本書。

參考資料

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號