參考網址:精讚部落格
瀏覽器對於網頁的語系判斷,網路上一堆文章在討論,不過我覺得不太正確,似是而非,所以我寫了這篇文章。
首先,大家都知道網頁的HEADER這行可以決定編碼方式,這個稱之為 META
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
html5
<meta charset="utf-8" />
大部分的瀏覽器如果編碼設成「自動偵測」時都能正確的分析,並以 utf-8 輸出。但世界並不會這麼平順完美,明明我這樣設定時,他就是用 big5 丟出來,或是我明明設定 META 為 big5,但是他丟出來卻是 utf-8,是不是我的瀏覽器不好,所以換了瀏覽器,也許仍不正常(或者是正常後開始罵不正常的瀏覽器爛)。
為何會如此?先來研究一下,在 APACHE 的 httpd.conf 及 php.ini 中都有指定編碼語系的方式,例如:
[httpd.conf]
AddDefaultCharset Big5
[php.ini]
default_charset = "iso-8859-1"
這個萬不得已是不應該去指定的,因為一旦指定,也許能解決一時的問題,但是未來接手管理的人,會毫無頭緒,不知道為什麼編碼怎麼設都不正確,找不出原因;或是同網站不同編碼的網頁,怎麼試都不正確。此外,如果在共用的空間中,更沒有辦法去修改 httpd.conf 或是 php.ini 的 charset,常會一個頭兩個大。
接下來我們來研究..
為什麼明明 META 就已經正確了,瀏覽器好像視而不見?
先來看看,如果在 httpd.conf 中或是php.ini 已經預設了編碼,瀏覽器取得網頁有什麼不同。這裡我們就要回到 http 這個協定一開始的定義點來看
Hypertext Transfer Protocol — HTTP/1.1 rfc 2612
瀏覽器在取得網頁內容之前,無論有無讀取過,都會進行一個 HEAD method 以檢查網頁是否有更新,以決定是否要 refresh。所以我們來看一下有定義 charset 和未定義 charset 時取回的 head 有何不同,特別注意,這個 HEAD 不是網頁裡的 < head></head>標籤中的東西,別搞錯了。
# telnet kt.example.com 80 Trying 114.33.4.124... Connected to example.com. Escape character is '^]'. HEAD / HTTP/1.1 Host:kt.example.com Connection: close HTTP/1.1 200 OK Date: Sat, 24 Apr 2010 06:44:14 GMT Server: Apache/2.2.9 (FreeBSD) mod_ssl/2.2.9 OpenSSL/0.9.8e DAV/2 PHP/5.2.6 with Suhosin-Patch X-Powered-By: PHP/5.2.6 Set-Cookie: PHPSESSID=v8hrfte7qvlhs8vmfeu4fgcch3; path=/ Expires: Thu, 19 Nov 1981 08:52:00 GMT Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0 Pragma: no-cache Connection: close Content-Type: text/html; charset=Big5 <== 注意看,多出這一行 Connection closed by foreign host.
由此可知,瀏覽器在 HEAD method 完畢後,就自動會切換成 Big5 的編碼,這時就算你在 <META> 中怎麼設定,瀏覽器全都視而不見啦,這和什麼 BOM 一點關係也沒有。
因為瀏覽器使用http的method,如GET、POST、HEAD…等方法去取回資料時,伺服器早就偷偷的寫說要「指定」什麼編碼來顯示,瀏覽器根本就不再理會你html中的meta指定編碼的那行。就算你怎麼設定,他就只會聽伺服器說的…