Nginx是一個免費開源且穩定高效的Web伺服器程式,經常用來提供HTTP網頁和靜態檔案等資源。但是有些人在使用Nginx的時候會碰到網頁或是文字檔用瀏覽器開啟時出現亂碼的問題,這該怎麼解決呢?
如下圖,在瀏覽器上開啟文字檔時,瀏覽器卻顯示了一堆亂碼。
當遇到這個問題的時候,可以先開啟瀏覽器自帶的網頁檢查工具,查看伺服器是否有回應Content-Type
標頭。如上圖,伺服器確實有回應Content-Type
標頭,內容如下:
預設情況下,Nginx可以辨識常見的檔案副檔名,來決定Content-Type
標頭的內容。但是Nginx自動填寫的Content-Type
標頭,只會有Mime類型的部份,並不會有charset
(字元集)的部份。因此只知道文件的Mime類型卻不知道其文字使用的編碼格式為何的瀏覽器,通常會直接使用「ISO-8859-1」這個編碼格式對其解碼,如果該文件本來就不是使用「ISO-8859-1」來編碼的,錯誤解碼後,瀏覽器就會顯示出亂碼啦!
為了解決這個問題,我們必須要讓Nginx伺服器告訴瀏覽器文件使用的編碼方式,也就是要在Content-Type
標頭中加上charset
的設定值。至於文件到底要使用什麼編碼方式比較好,其實也不用多想,就是用「UTF-8」,沒有例外!「UTF-8」是大部份程式語言內建的字串編碼方式,它只需要用很小的空間,就可以表達出世界上大部份語言所使用的文字。
所以要如何讓Nginx伺服器能在回應純文字文件的時候,在Content-Type
標頭中自動加上charset
的設定值呢?
我們需要修改Nginx的設定檔,在http
區塊或是其底下的server
或是location
區塊中使用Nginx提供的charset
命令,直接指定Content-Type
標頭的charset
的設定值為utf-8
。
charset utf-8;
如此一來,就可以讓charset_types
命令所指定的Mime類型,都在Content-Type
標頭中自動加上charset=utf-8
這個設定值。有了正確的charset
的設定值後,瀏覽器就不會再出現亂碼啦!
您可能會有疑問:「charset_types
命令所指定的Mime類型」到底有哪些呢?Nginx預設能夠在Content-Type
標頭中使用charset
設定值的Mime類型為text/html
、text/xml
、text/plain
、text/vnd.wap.wml
、application/javascript
和application/rss+xml
,也就是說,如果文件的Mime類型不在上述之列,就算使用charset
命令,也不能夠在Content-Type
標頭中加上charset
設定值。
如果需要自訂能夠使用charset
設定值的Mime類型,我們需要自行撰寫charset_types
命令。charset_types
命令的撰寫方式如下:
charset_types text/html text/xml text/plain text/vnd.wap.wml application/javascript application/rss+xml;
以上命令是Nginx的預設值,可以看到預設值並不包含所有的純文字文件。所以如果我們要讓charset
設定值能夠套用在所有純文字文件上,是不是只要把上面的命令改成以下這樣呢?
charset_types text/* application/javascript application/rss+xml;
以上命令看起來可行,也可以通過Nginx設定檔的檢查,但是charset_types
命令中的「text/*」並不會真的具有「星號表示所有類型」的功能。如果使用這個命令的話,所有以text/
開頭的Mime類型的文件都無法套用到charset
設定值。
為了解決這個問題,讓Nginx伺服器真的可以在回應所有類型的純文字文件時,在Content-Type
標頭中自動加上charset
的設定值,我們必須使用到map
命令和$sent_http_content_type
變數。Nginx的map
命令,可以判斷某值究竟是什麼值,來輸出另一個值到其它的變數。而$sent_http_content_type
變數,則是儲存目前要回應的Content-Type
標頭之內容。
結合之後,可以撰寫出如下的map
命令:
map $sent_http_content_type $charset {
default '';
~^text/ utf-8;
application/javascript utf-8;
application/rss+xml utf-8;
}
以上命令,當原本Nginx伺服器要回應的Content-Type
標頭的內容為application/javascript
、application/rss+xml
或是以text/
開頭時,就可以讓$charset
變數的值設為utf-8
;否則的話就設為空字串""
(同off
)。
接著使用charset_types
命令,將允許的Mime類型改為單獨的星號*
,使所有的Mime類型都可以被charset
命令控制。如下:
charset_types *;
然後再使用charset
命令,套用$charset
變數的內容給charset
設定值。如下:
charset $charset;
如此一來,就能真正讓Nginx伺服器在回應所有類型的純文字文件時,在Content-Type
標頭中自動加上charset
的設定值了!