posts - 495,comments - 227,trackbacks - 0
          http://www.jdon.com/40381


          Last-Modified和Expires針對瀏覽器,而ETag則與客戶端無關(guān),所以可適合REST架構(gòu)中。兩者都應(yīng)用在瀏覽器端的區(qū)別是:Expires日期到達前,瀏覽器不會再發(fā)出新的請求,除非用戶按瀏覽器的刷新,所以,Last-Modified和Expires基本是降低瀏覽器向服務(wù)器發(fā)出請求的次數(shù),而ETag更側(cè)重客戶端和服務(wù)器之間聯(lián)系。

          先談Last-Modified和Expires,最新的Tomcat 7 將ExpireFilter加入其容器中,這樣,Java WEB也可以象Apache的Mod_expire模塊一樣對Http頭部進行統(tǒng)一設(shè)置了,不過它只對響應(yīng)文檔類型進行統(tǒng)一設(shè)置判斷,如text/html或text/image 或/css等等,如果想對個別URL輸出的jsp進行定制就不行,urlrewrite據(jù)說是可以,但是要把URL在其配置文件再配置一下,麻煩,一旦jsp改動影響面大,還有一個問題就是web.xml配置了Tomcat 7容器的ExpireFilter,與容器耦合,移植性差(移植到Resin就不行了)。

          所以,我在JiveJdon 4.2最新版本中,通過加入下面一段代碼在服務(wù)器端對來自客戶端的Last-Modified以及當前時間進行判斷,如未過期,response.setStatus設(shè)為304,可以終止后面的各種Jsp界面計算,直接返回瀏覽器一個304的響應(yīng)包,JSP頁面也不會輸出到客戶端,將帶寬節(jié)省給更加需要互動實時性的請求。

          再談?wù)凟Tag,ETag定義:RFC2616(也就是HTTP/1.1)中沒有說明ETag該是什么格式的,只要確保用雙引號括起來就行了,所以你可以用文件的hash,甚至是直接用Last-Modified,以下是服務(wù)器端返回的格式:
          ETag: "50b1c1d4f775c61:df3" 客戶端向服務(wù)端發(fā)出的請求:If-None-Match: W/"50b1c1d4f775c61:df3" 這樣,在J2EE/JavaEE服務(wù)器端,我們判斷如果ETag沒改變也是返回狀態(tài)304,起到類似Last-Modified和Expires效果。

          與Last-Modified和Expires區(qū)別是:如果過了Expires日期,服務(wù)器肯定會再次發(fā)出JSP完整響應(yīng);或者用戶強按瀏覽器的刷新按鈕,服務(wù)器也必須響應(yīng),apache等靜態(tài)頁面輸出也是這樣,但是這時動態(tài)頁面就發(fā)揮了作用,如果JSP涉及的業(yè)務(wù)領(lǐng)域模型還是沒有更新,和原來一樣,那么就不必再將動態(tài)頁面輸出了(瀏覽器客戶端已有一份),從Etag中獲取上次設(shè)置的領(lǐng)域模型對象修改日期,和現(xiàn)在內(nèi)存中領(lǐng)域模型(In-memory Model)修改日期進行比較,如果修改日期一致,表示領(lǐng)域模型沒有被更新過,那么返回響應(yīng)包304,瀏覽器將繼續(xù)用本地緩存的該頁面,再次節(jié)省了帶寬傳輸。

          通過上述Expire和Etag兩次緩存,可以大大降低服務(wù)器的響應(yīng)負載,如果你的應(yīng)用不是狀態(tài)集中并發(fā)修改和實時輸出,而是分散修改然后分發(fā),如個人空間 個人博客(每個人只是修改它們自己的狀態(tài),不影響全局)或QQ類似個人工具,那么采取這樣的方法效果非常明顯,實際就是一種動態(tài)頁面靜態(tài)化技術(shù),但比通常事先進行頁面靜態(tài)化要靈活強大。

          InfoQ的那篇:http://www.infoq.com/articles/etags還用MD5計算放入其中,Md5計算稍微復雜點,負載大了點,有的人結(jié)合Hibernate或數(shù)據(jù)庫觸發(fā)器來判斷數(shù)據(jù)庫數(shù)據(jù)是否更新,以決定Etag的更新,這將表現(xiàn)層和持久層耦合在一起,由于JiveJdon采取的是MDD/DDD模型驅(qū)動架構(gòu),表現(xiàn)層的Etag更新是根據(jù)中間業(yè)務(wù)層的模型對象修改日期來決定,不涉及數(shù)據(jù)庫層,而且起到服務(wù)器緩存的更新和http的Etag更新一致的效果,在松耦合設(shè)計和性能上取得綜合平衡。

          代碼如下:

          public static boolean checkHeaderCache(long adddays, long modelLastModifiedDate, HttpServletRequest request, HttpServletResponse response) {
          // com.jdon.jivejdon.presentation.filter.ExpiresFilter
          request.setAttribute(
          "myExpire", adddays);

          // convert seconds to ms.
          long adddaysM = adddays * 1000;
          long header = request.getDateHeader(
          "If-Modified-Since");
          long now = System.currentTimeMillis();
          if (header > 0 && adddaysM > 0) {
          if (modelLastModifiedDate > header) {
          // adddays = 0; // reset
          response.setStatus(HttpServletResponse.SC_OK);
          return true;
          }
          if (header + adddaysM > now) {
          // during the period happend modified
          response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
          return false;
          }
          }

          // if over expire data, see the Etags;
          // ETags if ETags no any modified
          String previousToken = request.getHeader(
          "If-None-Match");
          if (previousToken != null && previousToken.equals(Long.toString(modelLastModifiedDate))) {
          // not modified
          response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
          return false;
          }
          // if th model has modified , setup the new modified date
          response.setHeader(
          "ETag", Long.toString(modelLastModifiedDate));
          setRespHeaderCache(adddays, request, response);
          return true;

          }

          public static boolean setRespHeaderCache(long adddays, HttpServletRequest request, HttpServletResponse response) {
          request.setAttribute(
          "myExpire", adddays);

          long adddaysM = adddays * 1000;
          String maxAgeDirective =
          "max-age=" + adddays;
          response.setHeader(
          "Cache-Control", maxAgeDirective);
          response.setStatus(HttpServletResponse.SC_OK);
          response.addDateHeader(
          "Last-Modified", System.currentTimeMillis());
          response.addDateHeader(
          "Expires", System.currentTimeMillis() + adddaysM);
          return true;
          }


          posted on 2013-09-26 17:35 SIMONE 閱讀(1840) 評論(0)  編輯  收藏 所屬分類: JSP
          主站蜘蛛池模板: 富裕县| 武功县| 固阳县| 铜山县| 湟源县| 泸水县| 东宁县| 汽车| 久治县| 祁连县| 上犹县| 河北省| 韶关市| 新宁县| 桂阳县| 宁明县| 灵台县| 东城区| 新河县| 昌都县| 益阳市| 介休市| 黔西县| 榆社县| 丹江口市| 垣曲县| 阳江市| 拉萨市| 光泽县| 富源县| 游戏| 屏南县| 德令哈市| 桑植县| 仁寿县| 理塘县| 琼海市| 隆安县| 东明县| 宁津县| 资溪县|