Spring mvc HTTP協議之緩存機制

概述

Spring MVC 支持HTTP協議的 Last-Modified 緩存機制。

  1. 在客戶端地一次輸入URL時,服務器端會返回內容和狀態碼200, 表示請求成功,同時會添加一個“Last-Modified”屬性,表示該請求資源的最後修改時間
  2. 客戶端第二次請求此URL時,客戶端會向服務器發送請求頭 “IF-Modified-Since”,如果服務端內容沒有變化,則自動返回HTTP304狀態碼(只返回相應頭信息,不返回資源文件內容,這樣就可以節省網絡帶寬,提供響應速度和用戶體驗)

Spring MVC 中實現示例

UserCacheController.java

@Controller
public class UserCacheController extends AbstractController implements LastModified{
    private long lastModified = System.currentTimeMillis();

    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response)
            throws Exception {

        List<User> userList = new ArrayList<User>();

        userList.add(new User("zhangsan", 18));
        userList.add(new User("wangwu", 16));

        System.out.println("執行一次,我有緩存");
        return new ModelAndView("userList", "users", userList);
    }

    @Override
    public long getLastModified(HttpServletRequest request) {
        //時間戳邏輯,返回最後修改時間,例如
        if (lastModified == 0L) {
            lastModified = System.currentTimeMillis();
        }
        System.out.println("時間戳:"+lastModified);
        return lastModified;
    }
}

Spring MVC 提供的Last-Modified機制的支持,只需要實現LastModified接口,並實現GetLastModified() 方法,每次修改資源的時候,更新下lastModified的值即可。

userList.jsp

<%@page import="java.util.List"%>
<%@page import="cn.com.infcn.bean.User"%>
<%@ page language="java" contentType="text/html; charset=utf-8"
    pageEncoding="utf-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Insert title here</title>
</head>
<body>
    <%
        List<User> userList = (List<User>) request.getAttribute("users");
        for (User user : userList) {
    %>
    用戶名:<%=user.getUserName()%><br /> 年齡:<%=user.getAge()%><br />
    <hr>
    <%
        }
    %>
</body>
</html>

訪問效果



只有第一次執行了Controller,以後訪問都沒執行Controller。

原理分析

DispatcherServlet.doDispatch()


  1. 首先獲取 http 請求的method type。
  2. 如果method 是 “GET”或“HEAD” 才支持緩存機制
  3. 通過 HandlerAdapter.getLastModified() 方法獲取 UserCacheController 中的lastModified 的值,最後修改時間。
  4. 調用 checkNotModified() 方法驗證 http 請求頭中的“If-Modified-Since”的時間進行對比,判斷頁面是否更新過。如果有更新才執行具體的Controller, 沒有更新則響應 304 狀態碼信息(HTTP 304: Not Modified )。

getLastModified()



通過handler的適配器類,然後在調用UserCacheController.getLastModified() 方法獲取最後更新時間。

checkNotModified()

Paste_Image.png
Paste_Image.png
  1. 調用 validateIfModifiedSince() 方法獲取http請求頭中的“If-Modified-Since”值,並驗證是否修改過。
    沒有修改過則設置notModified=true,如果修改過則設置notModified=false。
  2. 如果 notModified=true,則設置response響應狀態碼304或412
  3. 如果是GET 或 HEAD 請求則添加響應頭“Last-Modified”

validateIfModifiedSince()


  1. 解析http 請求頭中的“If-Modified-Since”值
  2. 判斷緩存頁面是否需要更新。
    注:(lastModifiedTimestamp / 1000 * 1000):因爲http頭中只保存到秒,所以這裏把秒後面的置爲0。

HTTP 請求響應頭分析



通過瀏覽器F12 可以看出:

  1. 每次請求都會攜帶“If-Modified-Since”信息到服務器驗證資源是否需要更新。
  2. 服務器響應頭中會包含“Last-Modified”信息,訪問資源最後修改的日期。

緩存限制條件

並不是所有MappingHandler 方式都支持緩存。
比如:DefaultAnnotationHandlerMapping 就不支持緩存機制。
因爲支持註解的Controller中可以有多個請求方法,而每個方法都需要計算文件的最後修改時間,這樣LastModified就不適用了。只適用一個Controller中只支持一個請求的HandlerMapping。

AnnotationMethodHandlerAdapter


從代碼中可以看出,這個方法永遠返回-1。



作者:jijs
鏈接:http://www.jianshu.com/p/1167a287772b
來源:簡書
著作權歸作者所有。商業轉載請聯繫作者獲得授權,非商業轉載請註明出處。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章