在路上

          姿勢就是力量

           

          struts2項目中靜態html在firefox下亂碼的解決

             struts2 項目,通常開發過程中,一些簡單的表單文件或者靜態描述頁面,能不走action流程就可以用html來做,可以一定程度上減少 struts2 的流程開銷,如果前端有apache的話,也可以進一步分攤業務服務器壓力。按照這樣的原則,一個系統做下來,難免有一些或者很多的靜態html文件。 
             在我的一個工程里面,所有文件的編碼格式均為 utf-8,包括這些靜態 html 文件。 在 IE 下訪問,頁面顯示完全沒有問題。用 httplook 查看 http 頭信息,也可以看到服務器回送的頁面字符集編碼為正常的 utf-8。 但是用 firefox 瀏覽的時候,所有的動態頁面(*.do)正常,唯獨 html 頁面全部亂碼,在瀏覽器菜單內手動選擇頁面編碼格式為 utf-8,則可以正常顯示中文了。雖然可以暫時解決,但不可能假設所有的用戶每次瀏覽這些靜態html的時候,都會手動去選擇編碼格式。這里必須要有一個治本的辦法。 
              在firefox內亂碼的html頁面上,右鍵“查看頁面信息”,可以看到http頭信息內的編碼格式為 gb2312,而頁面meta信息內指定的是utf-8。即firefox是按gb2312的缺省行為來解析utf-8編碼的頁面,當然會亂碼。問題就出在,firefox并不會像IE那樣可以根據meta信息覆蓋服務器回送的http頭信息,它是嚴格按照http協議規范的行為方式:按照http頭指定的編碼格式來解析頁面。也就是說,如果http頭回送里面指定了頁面的編碼格式,firefox會忽略meta信息的字符集指定。而IE則以meta優先。
              為什么我的服務器輸出html頁面的時候,http頭會回送gb2312的編碼集?我在 web.xml 內加上 SetCharacterEncodingFilter,強制所有輸出字符集為 utf-8,問題依舊。因為項目做了 SEO,用到了 UrlRewriterFilter,便懷疑是這個 filter 在做 url forward 的時候,改變了輸出字符集,可是去掉這個 filter 后,問題還是存在。 于是再考察struts2的 FilterDispatcher,這是一個全局的派發過濾器,struts2的核心派發控制器。 最初的配置如下:
             

          <filter>
                  
          <filter-name>struts2</filter-name>
                  
          <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
              
          </filter>
              
          <filter-mapping>
                  
          <filter-name>struts2</filter-name>
                  
          <url-pattern>/*</url-pattern>
                  <dispatcher>REQUEST</dispatcher>
                  <dispatcher>FORWARD</dispatcher>
              </filter-mapping>

          url-pattern 是 /* 的全范圍映射,當然也包括了 html 后綴文件。這種情況下,項目中任何一個請求,會經過3次filter,首先是SetCharacterFilter、然后是 UrlRewriterFilter、最后是 FilterDispatcher,之前已經排除了 UrlRewriterFilter 的問題。于是修改 FilterDispatcher 的 url-pattern 為 *.do,即只過濾 *.do 的請求,其他請求比如 *.html,則不會經過這個 filter。 
              這樣修改后,一切都正常了。
              
              當 url-pattern 為 /* 時,所有請求包括對靜態資源文件的請求,都會有FilterDispatcher來接管派發。如果請求類型為靜態資源,則 FilterDispatcher 不會調用 action 處理模塊來接收這個請求,而是簡單的回送靜態資源。在這個回送過程中,FilterDispatcher 做的工作如下:

          FilterDispatcher.java
          protected void findStaticResource(String name, HttpServletRequest request, HttpServletResponse response) throws IOException {
                  
          if (!name.endsWith(".class")) {
                      
          for (String pathPrefix : pathPrefixes) {
                          InputStream is 
          = findInputStream(name, pathPrefix);
                          
          if (is != null{
                              Calendar cal 
          = Calendar.getInstance();
                              
                              
          // check for if-modified-since, prior to any other headers
                              long ifModifiedSince = 0;
                              
          try {
                                  ifModifiedSince 
          = request.getDateHeader("If-Modified-Since");
                              }
           catch (Exception e) {
                                  LOG.warn(
          "Invalid If-Modified-Since header value: '" + request.getHeader("If-Modified-Since"+ "', ignoring");
                              }

                              
          long lastModifiedMillis = lastModifiedCal.getTimeInMillis();
                              
          long now = cal.getTimeInMillis();
                              cal.add(Calendar.DAY_OF_MONTH, 
          1);
                              
          long expires = cal.getTimeInMillis();
                              
                              
          if (ifModifiedSince > 0 && ifModifiedSince <= lastModifiedMillis) {
                                  
          // not modified, content is not sent - only basic headers and status SC_NOT_MODIFIED
                                  response.setDateHeader("Expires", expires);
                                  response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
                                  is.close();
                                  
          return;
                              }

                              
                              
          // set the content-type header
                              String contentType = getContentType(name);
                              
          if (contentType != null{
                                  response.setContentType(contentType);
                              }


                              
          if (serveStaticBrowserCache) {
                                  
          // set heading information for caching static content
                                  response.setDateHeader("Date", now);
                                  response.setDateHeader(
          "Expires", expires);
                                  response.setDateHeader(
          "Retry-After", expires);
                                  response.setHeader(
          "Cache-Control""public");
                                  response.setDateHeader(
          "Last-Modified", lastModifiedMillis);
                              }
           else {
                                  response.setHeader(
          "Cache-Control""no-cache");
                                  response.setHeader(
          "Pragma""no-cache");
                                  response.setHeader(
          "Expires""-1");
                              }


                              
          try {
                                  copy(is, response.getOutputStream());
                              }
           finally {
                                  is.close();
                              }

                              
          return;
                          }

                      }

                  }


                  response.sendError(HttpServletResponse.SC_NOT_FOUND);
              }


          // ..

          protected InputStream findInputStream(String name, String packagePrefix) throws IOException {
                  String resourcePath;
                  
          if (packagePrefix.endsWith("/"&& name.startsWith("/")) {
                      resourcePath 
          = packagePrefix + name.substring(1);
                  }
           else {
                      resourcePath 
          = packagePrefix + name;
                  }


                  resourcePath 
          = URLDecoder.decode(resourcePath, encoding);

                  
          return ClassLoaderUtil.getResourceAsStream(resourcePath, getClass());
              }


          可以看到,由 ClassLoaderUtil.getResourceAsStream 載入靜態資源,然后回送。ClassLoaderUtil 還是用了 xwork 的 lib,struts2并沒有重寫這個類。這個回送過程中,FilterDispatcher 并沒有指定回送字符集,因此輸出頁面會采用服務器默認字符集,當然跟具體操作系統也有關系。目前還沒看到有默認以UTF-8作為服務器字符集的。

          posted on 2007-09-23 15:10 Samuel.Mo 閱讀(4313) 評論(0)  編輯  收藏 所屬分類: Java


          只有注冊用戶登錄后才能發表評論。


          網站導航:
          博客園   IT新聞   Chat2DB   C++博客   博問  
           

          導航

          統計

          常用鏈接

          留言簿(1)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 南木林县| 宝丰县| 随州市| 沅江市| 工布江达县| 保康县| 武夷山市| 高碑店市| 苍南县| 平远县| 通化市| 涟水县| 交城县| 溆浦县| 胶南市| 齐河县| 哈尔滨市| 五常市| 恩平市| 安达市| 天镇县| 姚安县| 中牟县| 收藏| 湛江市| 嘉兴市| 会东县| 阜南县| 雷波县| 辽宁省| 綦江县| 秦皇岛市| 垫江县| 米泉市| 通化县| 资溪县| 冕宁县| 白玉县| 额敏县| 修水县| 开封县|