web開發編碼問題

關於在web開發過程中的編碼問題


前言

昨天小編寫的一個小的表單提交程序發現了亂碼的問題,雖說以前也碰到過,而且這次解決起來也挺快,但是也一直沒有認真的去想過這個問題,究竟從表單提交到服務器端響應請求這中間的編碼機制到底是怎樣?

先拋幾個問題:

  • 爲什麼有時候<meta charset="utf-8">不太管用?
  • html頁面的編碼方式究竟由什麼決定?
  • 各瀏覽器對編碼的處理一樣嗎?

更改html頁面編碼

因爲小編百度了無數遍後感覺答案很多,不夠統一,各有各的說法。所以直接上W3C官網去查看相關的標準和文檔。下面的內容大多來自於W3C官網和小編自己的測試。

英文好的同學可以直接看W3C文檔:W3C文檔

迴歸正題,指定網頁的編碼如下代碼:

<html>
    <head>
        <meta charset="utf-8">
        ...
    </head>
...
</html>

上面的代碼應該人人都知道把,但是好像有時候並不是什麼時候都管用,至於爲什麼等一下會說。

還有第二種方式就是:

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

有些人可能兩條都聲明在了html頭那裏了,但是其實這兩種寫法選其中一種就行了,因爲這兩條語句表達的是一樣的,只是第一條比第二條要簡單一點。而且utf-8跟UTF-8也是一樣的,二選一就好了,下面是W3C原話:

It doesn’t matter which you use, but it’s easier to type the first one. It also doesn’t matter whether you type UTF-8 or utf-8.

在進行了編碼聲明過後文件也應該以相應的編碼保存在磁盤。

W3C是推薦大家都採用utf-8編碼網頁,W3C自家網站也是用utf-8編碼的。

ISO-8859-1編碼(亂碼)

注意:如果meta聲明成<meta charset="ISO-8859-1">的,在處理中文表單時會出問題(服務器端亂碼)

因爲ISO-8859-1編碼並不能夠去編碼中文的字符,所以如果在聲明爲ISO-8859-1編碼的文檔裏提交中文表單的話會先把中文的字符轉換成utf-8的字符串,然後再把utf-8的字符串編碼進URL然後發送請求到服務器,所以最終在服務器端URL解碼後得到的其實是經utf-8編碼後的字符串。

下面舉個例子:如果我在表單輸入“你好”兩個中文,因爲這時候聲明的ISO-8859-1編碼無法編碼中文,所以會把中文編碼成utf-8字符串,那中文的utf-8表示是&#x4F60;&#x597D;,這時候就沒有特殊字符了,字符串裏面都是ISO-8859-1可以編碼的,所以直接就可以把&#x4F60;&#x597D;只是把#,&這些特殊字符換成%23,%26編碼進URL,編碼後的URL是%26%2320320%3B%26%2322909%3B,所以當在服務器端解碼的時候,得到的其實只是&#x4F60;&#x597D;這個字符串,並不是中文“你好”這兩個字。

所以處理中文請不要聲明爲ISO-8859-1編碼,用utf-8就好了。

編碼優先級

HTTP響應頭優先級

好了,這裏就來解決上面提出的問題,有些時候可能我們會發現在html文檔的head裏聲明<meta>標籤沒什麼用,爲什麼會這樣。

這裏涉及到一個優先級問題,在W3C的文檔裏面明確表示如果瀏覽器收到HTTP響應頭的情況下,而且在HTTP相應頭中聲明瞭文檔的編碼的話,那麼HTTP響應頭的編碼的優先級會比在文檔中聲明的編碼的優先級高

W3C原話:

If you have access to the server settings, you should also consider whether it makes sense to use the HTTP header. Note however that, since the HTTP header has a higher precedence than the in-document meta declarations, content authors should always take into account whether the character encoding is already declared in the HTTP header. If it is, the meta element must be set to declare the same encoding.

可以在瀏覽器開發者模式中查看瀏覽器收到的網頁的HTTP響應頭

所以這就意味着如果服務器設置了響應頭Content-Type:text/html; charset=ISO-8859-1那麼就算在head中聲明瞭<meta charset="utf-8">根據HTTP頭的優先級要比HTML文檔中聲明的優先級高,那麼這時候頁面就按照ISO-8859-1編碼,中文就會亂碼了。而且設置HTML中的<meta>解決不了問題,問題在HTTP響應頭優先級更高。

BOM優先級

BOM留到最後講,因爲可能有點複雜,注意這裏的BOM不是JS裏面的BOM模型,這裏說的BOM是byte-order mark

BOM中文名稱“字節順序標記”,是一種文檔標記,標記在文檔頭部。

因爲utf-16或utf-32,…,等的編碼是等長的,就是說是操作2個字節或4個字節,所以在計算機裏面就涉及到了一個多字節如何儲存在內存中的概念。就好像在一些編程語言中的整形int=1;,那麼在英特爾系列的處理器中是按小段法儲存的,即01 00 00 00(16進制),低位字節在前高位字節在後的即爲小段法。一些處理器採用大端發,如果00 00 00 01即是大端法,高位在前低位在後。讀者也可以自己驗證,在C語言中強制將整形指針轉化爲char指針,打印單個字節,可以看到在英特爾CPU的機器中低位字節是放在前面的,高位字節是放在後面的,即採用小端法。

好了,那麼對於多自己的字符處理仍然有關於字節序的概念,這就是BOM標記的由來。

編碼 表示(十六進制)
utf-8 EF BB BF
utf-16(大端) FE FF
utf-16(小端) FF FE
utf-32(大端) 00 00 FE FF
utf-32(小端) FF FE 00 00

所以當檢測到文件頭部的標誌,計算機就能夠知道要用大端還是小端來解析這些字節了。

而且注意:根據W3C文檔,BOM標記具有最高的編碼優先級
下面是W3C原話:

If you have a UTF-8 byte-order mark (BOM) at the start of your file then recent browser versions other than Internet Explorer 10 or 11 will use that to determine that the encoding of your page is UTF-8. It has a higher precedence than any other declaration, including the HTTP header.
(注意:IE10和11無效)

也就是說假如文檔有BOM標記,那麼瀏覽器會檢測出文檔頭部的BOM標記,將用BOM標記的編碼格式來編碼文檔,BOM標記的優先級要高於HTTP響應頭和文檔內部<meta>標記

所以有些文件如果有BOM標記,那麼不管是改HTTP響應頭或者改文檔內部聲明都是無效的,因爲文檔BOM標記優先級最高。

說個題外話


關於utf-8編碼的文件有一些是有BOM標記,有一些則沒有BOM標記。微軟的軟件大多在保存utf-8編碼文件的時候都在文件頭添加了三個字節的BOM標記。小編也親測了,分別用windows的記事本和eclipse創建兩個utf-8編碼的html文檔,然後讀取文件的頭三個字節,毫無疑問,windows的記事本的確在文件的頭部添加了三個字節的標記,而eclipse創建的文檔則沒有添加頭部標記。

其實從上面的表格可以看出來utf-8編碼的BOM只有一種形式,大可以省略。並且因爲utf-8其實是一種變長的編碼,從1字節到4字節。所以操作的字節單位是單字節,並沒有字節序的概念,所以也就沒必要添加頭部標記。

而且一些添加了BOM頭部的文檔並不是在所有地方都兼容,例如在php中並不會忽略前面的頭部字節,所以最終文檔在瀏覽器中的表現會很奇怪。


總結

表單的處理跟文檔編碼一致。

而文檔的編碼有優先級關係:文檔BOM標記 > HTTP響應頭設置 > 文檔內部聲明(<meta>元素


喜歡我們的內容,關注我們的公衆號吧
這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章