自動目錄
強迫網頁預設編碼語系
瀏覽器對於網頁的語系判斷,網路上一堆文章在討論,不過我覺得不太正確,似是而非,所以我寫了這篇文章。
首先,大家都知道網頁的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>標籤中的東西,別搞錯了。
我們來用最原始的定義進行 http 通訊,這時我心愛的 Freebsd 又要上場了,我在上面建立兩個網站:
[測試參數]
1. 網站 ktu.example.com (偽) META utf-8 編碼,系統未設定任何預設編碼方式
2. 網站 kt.example.com (偽) META utf-8 編碼,系統預設 big5 編碼方式如下(設定在網站 / 目錄的 .htaccess):
<IfModule mod_autoindex.c>
IndexOptions Charset=Big5
</ifModule>
[測試]
以下直接用 HEAD 方法取得的內容,注意黃色字是自己下的指令:
測試 1. ktu.example.com
# telnet ktu.example.com 80
Trying 114.33.4.124...
Connected to example.com.
Escape character is '^]'.
HEAD / HTTP/1.1
Host:ktu.example.com
Connection: close
HTTP/1.1 200 OK
Date: Sat, 24 Apr 2010 06:43:37 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=m1da8jd9d5rsca810as44qoah1; 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
Connection closed by foreign host.
測試 2 . kt.example.com
# 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指定編碼的那行。就算你怎麼設定,他就只會聽伺服器說的...
但為什麼有些瀏覽器很聰明,會用我指定的編碼?
常常會聽到同事或朋友質疑我的說法,他們說,有些瀏覽器還是能正確顯示,某些的不正常(順便會酸一下XXX很爛,白痴才在用…),為什麼會這樣?
對的,你可能忘記一件事,就是你第一次顯示不正常的時候,你有沒有「手動」去更換過編碼?如果有的話,這就是原因。因為某些瀏覽器記住你的「習慣」,而不是他真的很聰明到能做出判斷。
原文 2010-04-24 14:27:04
原文沒寫到解決方法,這裡寫一下你可以試著讓他使用正確的編碼的方法:
在火狐的「工具」->「頁面資訊」可看到指定的編碼
這上面如果有看到「文字編碼」的話,就是伺服器送出的指定編碼
上圖可以看到伺服器已指定Big5,後設資料中的編碼utf-8(meta中設定)就被完全的忽略了。
如果不是你指定的編碼,請檢查你的httpd.conf/.htaccess/php.ini等設定檔,是不是有設定到,請把他們移除。