在上一篇說完了如何通過文檔內的編碼聲明來確定網頁的編碼通過文檔內的編碼聲明來確定網頁的編碼,這一篇則開始具體講述如何通過響應頭下的 Content-Type 條目中的 charset 信息來確定文檔的編碼,包括如何去配置這個響應頭,以及一些具體的實驗,還有它與文檔內編碼聲明的優先級選擇問題。
content-type 中的 charset
通過前面的介紹,你已經知道了所謂的“響應頭下的 Content-Type 條目中的 charset 信息”,就是這樣:
或這樣的東西:
它指出了這段響應流的編碼。
響應頭的優先級爲什麼更高?
前面已經說到,它的優先級是要高過文檔內編碼聲明的。這其實也很好理解,因爲它屬於外部信息,而文檔內編碼聲明則屬於內部信息。
上一篇說到,瀏覽器還要通過嗅探算法才能獲取到文檔內的編碼聲明。
所以,如果服務端的響應已經直接告訴你這段響應流的編碼,你都不用去“嗅探”了,瀏覽器自然很樂意直接採用它。
也可以這樣理解,這個編碼的頭信息服務端是可以不發送的,現在反而專門主動地告訴你,怕你不知道,自然它的可信度也是很高的。瀏覽器優先採用它也不足爲奇了,還省略了嗅探的步驟,提高了效率。
配置靜態頁面的響應頭編碼
前面說到,當在 tomcat8 缺省配置下運行時,它不會爲 Content-Type 中增加編碼信息:
我們需要主動去配置這個信息。具體而言,可以去到工程的 web.xml 下,增加一個 mime-mapping 配置:
<mime-mapping>
<extension>html</extension>
<mime-type>text/html;charset=utf-8</mime-type>
</mime-mapping>
這裏,extension 表示文件的擴展名(後綴名),而 mime-type 中的內容則成爲 Content-Type 的值,如此,就增加了編碼的信息。
web.xml 最終結果如下:
當然,不同的 web server 間具體配置的語法會有所區別,如果用的不是 tomcat,你可以查詢相應文檔瞭解。
這樣一來,所有對 html 的靜態請求,響應頭就會變成這樣:
顯然,這樣的一個配置是一個工程全局級別的,
注意:如果你直接修改 tomcat server 的相關配置文件,就會成爲服務器級別的,將影響它下面部署的所有工程!
這時你要保證工程下所有的 html 文件都是使用 utf-8 來編碼的,否則由於它具有更高的優先級,那些比如 gbk 編碼的文檔將會發生亂碼,在上一篇中的實驗中也已經證實了這一點:
在開發實踐中應該遵循“審慎”原則,當你做某項調整時,要清楚知道它的後果。你不能光顧着解決自己當下碰到的問題,還要留心是否會引發更多的問題,也即是人們常說的“按下葫蘆浮起瓢”。很不幸的,碰到亂碼問題時,我們經常是“病急亂投醫”,而這點又往往是因爲我們對編碼問題沒有一個整體認識所導致的。
配置動態響應的響應頭編碼信息
如果說靜態的響應頭配置在 tomcat8 中顯得還不是很靈活,那麼在動態的響應中,你則可以自由地根據需要調整。比如這樣:
或者這樣:
文檔中也可以省略 meta charset 聲明瞭。當然,現在你要注意的依舊是要保證宣稱編碼與實際所用的一致:
正如上面兩圖中紅線標註的那樣,宣稱是 utf-8,實際也得是 utf-8;宣稱是 gbk,實際也得是 gbk。
不管是文檔內的還是文檔外的,保持一致性才能避免亂碼的發生。以上兩種情況下,文檔都能瀏覽器中正確顯示:
假如不一致:
結局依然是亂碼:
以上,爲每個請求都單獨設置了響應頭信息,能夠做到很靈活的設置。但有時我們可能也不想處處都要這樣弄一下,對於動態響應,同樣可以對全局(或者更小一點的局部)做一個統一配置,這點可以通過 filter 來做到。不過這些不是這裏談論的重點,這裏也是稍微提下。
優先級測試
通過動態響應,很容易構建一個衝突的編碼聲明的例子:
如上,Content-Type 中是 utf-8,文檔內聲明 meta charset 是 gbk,實際是 utf-8。
最終,顯示是正常的:
雖然 meta charset 給出了一個錯誤的建議,但 Content-Type 的優先級更高,瀏覽器先採納了它,忽略了文檔內的聲明。
反之,如果優先級更高的 Content-Type 給出了錯誤的建議,頁面就會亂碼了,具體代碼及演示略,讀者可以自行構建類似的測試。
另:我這裏一直用的是 Java 平臺來演示,但這些 meta 呀,headers 呀,Content-Type 呀,response 呀之類的都是跟平臺無關的,屬於 html 規範或 http 協議範疇,無論你是 php,asp 還是 nodejs 等等,與這些相關的東西都是類似的,原理也是相通的。如果你不是 Java 平臺,應該也不難構建類似的測試。
關於通過響應頭下的 Content-Type 條目中的 charset 信息來確定文檔的編碼就介紹到這裏,下一篇將討論 BOM 存在時的頁面編碼的確定問題。