遇到了一個問題:grails 項目中的 html 文件,瀏覽器打開全亂碼。這些 html 文件全是 UTF-8 編碼的,也有
頭了。java 開發 web 亂碼不在是問題的情況下,還讓我遇到這事。
一個怪現象:瀏覽器里指定 GBK 編碼可以正常顯示(可以懷疑與平台有關);不帶 index.html 的方式(即直接訪問路徑),如 http://localhost:8080/grails-test/ 又是另一套亂碼(即亂碼不一致,瀏覽器不能校正的)。
找問題根源吧 ……
開始懷疑 jetty 對 UTF-8 html 文件支持不好,打 war 放到 tomcat 看看,問題依舊。可排除 jetty 正常的。
接著懷疑整個 grails 項目,在 tomcat 新開一個普通的項目,加個幾個 utf-8 的 html 文件,訪問正常。很有可能 grails 項目中的某些過慮器作的怪。
這問題肯定是與使用了與平台有關的編碼相關方法,把編碼相關的操作設置平台無關的吧,可以用下面的 java 系統屬性,在 tomcat 下設置屬性如 bin/catalina.bat:
set JAVA_OPTS=%JAVA_OPTS% -Dfile.encoding=utf-8 -Ddefault.client.encoding=utf-8 -Duser.language=zh -Duser.region=CN
運行後沒問題,正常顯示。但還有一個怪現象,沒弄明白:用 gsp 生成的頁面保存為 utf-8 的 html 文件又可正常訪問。對比兩個 html 文件,沒發現有什麼不妥的地方。
還是 google 下吧:grails html 亂碼。恩,有重要提示:靜態html在sitemesh中亂碼的解決方法 ,但是,我不想在啟動時設置系統(不想干擾其它程序),我想到在 grails 的 BootStrap init 中設置系統屬性。設置如下:
classBootStrap {
definit = { servletContext ->
System.setProperty("file.encoding","UTF-8")
System.setProperty("default.client.encoding","UTF-8")
System.setProperty("user.language","zh")
System.setProperty("user.region","CN")
}
defdestroy = {
}
}
class BootStrap {
def init = { servletContext ->
System.setProperty("file.encoding", "UTF-8")
System.setProperty("default.client.encoding", "UTF-8")
System.setProperty("user.language", "zh")
System.setProperty("user.region", "CN")
}
def destroy = {
}
}
但還是亂碼,於是我再仔細對比上面提到的兩種 html 文件(一個我加的,有亂碼,叫 A.html;一個是 gsp 生成手動保存下來的,不會亂碼),然後嘗試
保存到 A.html 里。奇蹟出現,不會亂碼了。鬱悶 sitemesh 會這樣,可能是 grails 過的原因。
後來把 BootStrap init 中的編碼設置去了,發現 A.html 也可正常,因為 A.html 返回頭(或 meta 標籤指定了)有正確的編碼。但在這情況下有亂碼:不帶 index.html 的方式(即直接訪問路徑),上面提到的。用
curl -I http://localhost:8080/grails-test/
返回 Content-Type: text/html; charset=iso-8859-1。這樣不得不在 BootStrap init 加上編碼相關的系統屬性。
小結:
在 html 中用確meta layout 的元素的聲明,同時在 Grails 的 BootStrap init 中設置編碼相關的系統屬性。
另一種簡單的方法:直接在服務啟動級別設置編碼相關的系統屬性,這樣 html 也不用 layout 聲明。