resin3.1處理utf-8格式的jsp時存在的問題

    以前一直使用resin-3.0.x作爲服務器,最近想升級到resin3.1,於是在官網上下載了resin3.1.7a,解壓配置一切正常,但把應用重新部署上去的時候就出了問題,以前一直正常的頁面,現在卻報錯:

 

500 Servlet Exception

 

<script type="text/javascript"><!----></script>
[show] /index.jsp:1: contentType 'text/vnd.wap.wml; charset=utf-8' conflicts with
previous value of contentType 'text/html; charset=UTF-8'.  Check the .jsp
and any included .jsp files for conflicts.

1:  <%@page contentType="text/vnd.wap.wml; charset=utf-8"%>
2:  <%@page import="java.util.*"%>
3:  <%!

 

 

    根據上面的提示,意思似乎是我在jsp裏面第一行設置的contentType是'text/vnd.wap.wml; charset=utf-8,和前面設置的'text/html; charset=UTF-8'不同導致衝突,但這個文件的第一行就是<%@pagecontentType="text/vnd.wap.wml;charset=utf-8" %>,根本沒有設置過'text/html; charset=UTF-8',這個提示真是讓人很摸不着頭腦。

    後來想到可能是UTF8文件格式的問題,就用UE打開文件,另存了一次,選的是不帶BOM的UTF8格式的文件,這次就可以正常顯示了。但服務器上那麼多文件,不可能一個一個的改,還得想其他的辦法解決。在網上找了很久都沒有任何頭緒,似乎遇到這個問題的人很少。

    最後實在是沒辦法,只好把源代碼下載下來研究一下看了,還真的找出了原因所在。

    因爲resin在處理jsp文件的時候,會首先讀取前面的幾個字節來判斷文件的格式,如果第一個字節是0xef、第二個字節是0xbb、第三個字節是0xbf,那麼就認爲這個文件是UTF8格式,於是就自作主張的把ContentType設置成了text/html; charset=UTF-8,然後在後面的處理過程中,因爲jsp程序裏面會有設置ContentType的指令,遇到這個指令會發現和之前的text/html; charset=UTF-8不同,因此就拋出了異常。而如果沒有BOM格式的UTF8,前面就不會有那三個字節的標識,所以就不會被處理了。

    相關代碼:

Java代碼  收藏代碼
  1.    case 0xef:  
  2.      if ((ch = stream.read()) != 0xbb) {  
  3. stream.unread();  
  4. stream.unread();  
  5.      }  
  6.      else if ((ch = stream.read()) != 0xbf) {  
  7. throw error(L.l("Expected 0xbf in UTF-8 header.  UTF-8 pages with the initial byte 0xbb expect 0xbf immediately following.  The 0xbb 0xbf sequence is used by some application to suggest UTF-8 encoding without a directive."));  
  8.      }  
  9.      else {  
  10. _parseState.setContentType("text/html; charset=UTF-8");  
  11. _parseState.setPageEncoding("UTF-8");  
  12. stream.setEncoding("UTF-8");  
  13.      }  
  14.      break;  

 

    判斷衝突的代碼:

  

Java代碼  收藏代碼
  1. else if (CONTENT_TYPE.equals(name)) {  
  2.     String oldContentType = _parseState.getContentType();  
  3.       
  4.     if (oldContentType != null && ! value.equals(oldContentType))  
  5.       throw error(L.l("contentType '{0}' conflicts with previous value of contentType '{1}'.  Check the .jsp and any included .jsp files for conflicts.", value, oldContentType));  
  6.       
  7.     _parseState.setContentType(value);  
  8.     String charEncoding = parseCharEncoding(value);  
  9.     if (charEncoding != null)  
  10. parseState.setCharEncoding(charEncoding);  
  11.   }  

 

真不明白爲什麼resin要這麼做呢,如果是web網站可能影響不大,contentType本來就是text/html,但如果是wap或者其他contentType的站點這麼“智能”的編碼判斷方式問題就比較麻煩了。

 

 

附:UTF-8 編碼的文件可以分爲no BOM 和 BOM兩種格式(轉載)

何謂BOM? "EF BB BF" 這三個字節就叫BOM,BOM的全稱叫做"Byte Order Mard".在utf-8文件中常用BOM來表明這個文件是UTF-8文件,而BOM的本意實在utf16中用來表示高低字節序列的。
在字節流之前有BOM表示採用低字節序列(低字節在前面),而utf8不用考慮字節序列,所以其實有無BOM都可以。


微軟的記事本 Word 等只能正確打開含BOM的UTF8文件,然後UltraEdit卻恰恰相反,回把BOMutf8文件 誤認爲ascii編碼。


UTF-8的BOM是 EFBBBF,因爲UE載入UTF-8文件會轉成Utf16,上述的EFBBBF 在Utf16中是FFFE(Unicode-LE的BOM),UltraEdit不認識BOM又加多一個BOM,所以有2個FFFE。
文件就被它破壞了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章