Java 實戰介紹 Cookie 和 Session 的區別

2023-06-13 09:00:19

HTTP 是一種不儲存狀態的協定,即無狀態協定,HTTP 協定不會儲存請求和響應之間的通訊狀態,協定對於傳送過的請求和響應都不會做持久化處理。

無狀態協定減少了對服務壓力,如果一個伺服器需要處理百萬級使用者的請求狀態,對伺服器的壓力無疑的是巨大的。

無狀態的 HTTP 由於其簡單和易用性,應用比較管廣泛。而且早期的 Web 服務對於狀態的需求也很低,所以應用場景也比較廣泛。

隨著 Web 的不斷髮展,越來越多的服務需要記錄使用者的登入狀態,比如購物、聊天、論壇服務,請求都是無狀態的服務,伺服器就無法識別是 HTTP 請求的使用者資訊,所以就需要一種技術儲存使用者的狀態,也就 Cookie 技術,有了 Cookie 的 HTTP 協定通訊,就能儲存狀態了。

Cookie

在無狀態協定不受影響的基礎上,通過引入 Cookie 來記錄狀態,這樣既不會影響原有的功能,也可以解決請求狀態問題。Cookie 是當你瀏覽網頁,通過伺服器記錄你的使用者名稱,密碼等網頁資訊。

Cookie 是由伺服器端建立,使用者端向服務傳送請求後,伺服器端通過響應報文的Set-Cookie 欄位將 Cookie 資訊返回給使用者端,使用者端自動儲存 Cookie。Cookie 會標記來源、有效期、路徑等資訊。使用者端再次請求該伺服器端時,會自動將 Cookie 新增到請求報文中(Request Header),伺服器端就能通過傳遞的 Cookie 識別使用者端的資訊。

1.沒有 Cookie 資訊的請求

2.再次(有了Cookie資訊後)傳送請求

使用 Spring Boot 建立簡單的 Controller,當用戶端傳遞的引數 a 有值時,伺服器端才新增 Cookie:

@GetMapping("/cookie")
@ResponseBody
public String cookie(String a, HttpServletRequest request, HttpServletResponse response) {
    if (a != null) {
        Cookie cookie = new Cookie("name",a);
        response.addCookie(cookie);
    }
    return "ok";
}

首先使用 Chrome 瀏覽器傳送請求http://localhost:8080/cookie:

返回結果沒有 Cookie。

再傳送帶有 a 引數的請求http://localhost:8080/cookie?a=jeremy:

返回 Cookie 都存在 Set-Cookie 欄位中,使用者端會自動儲存 Cookie。

再次傳送相同的請求http://localhost:8080/cookie?a=jeremy:

請求會將使用者端的 Cooike 自動新增到請求報文中,此時伺服器端也能接收到 Cookie資訊:

Session

Session 是伺服器端儲存使用者狀態的一種機制,當用戶存取網站時,伺服器端會為每個使用者建立唯一個對談標識,並根據使用者登入請求建立和儲存對談資訊,使用者端再次請求時,就能從伺服器端獲取對談資訊了。

Session 簡單實踐

在 Java 中的 Servlet 提供 HttpSession 的介面來操作對談資訊,只要有以下幾個方法:

  • public HttpSession getSession() 獲取對談資訊,如果不存在就建立對談資訊。
  • public String getId() 獲取唯一的對談 id。
  • public void invalidate() 將對談資訊失效,一般登出時候使用。

HttpSession 介面通過 getAttribute() 和 setAttribute() 來獲取和設定對談資訊,
下面建立兩個方法,session() 方法獲取對談判斷使用者是否登入,login() 方法新增對談資訊。

@GetMapping("/session")
@ResponseBody
public String session(HttpServletRequest request, HttpServletResponse response) {
    HttpSession session = request.getSession();
    Boolean login =(Boolean) session.getAttribute("login");
    String loginInfo;
    if (login == null) {
        loginInfo = "未登入";
    } else {
        loginInfo = "已登入";
    }
    return "session id :" + session.getId() + ":" + loginInfo;
}

@GetMapping("/login")
@ResponseBody
public String login(HttpServletRequest request) {
    HttpSession session = request.getSession();
    session.setAttribute("login",true);
    return "ok";
}

先請求 http://localhost:8080/session,返回如下資訊:

session id :F3C560208A54E3D5B465CDEBE7419817:未登入

多次傳送請求,session id 是一致的,說明 session id是在對談週期之內(瀏覽器不關閉)都是不變的。

然後請求登入介面 http://localhost:8080/login,設定了對談資訊之後,再請求 http://localhost:8080/session:返回如下資訊:

session id :F3C560208A54E3D5B465CDEBE7419817:已登入

同一個使用者請求,伺服器端會建立唯一的對談,在請求的生命週期之內,對談 id 一直不改變。session 對談由伺服器端新增後,後續請求就能獲取到對談資訊,對談資訊只儲存在伺服器端。

Cookie 和 Session 的區別

Cookie 是儲存在使用者端上小型文字,是由伺服器端建立,然後通過響應報文的 Set-Cookie 欄位返回給使用者端。使用者端每次請求伺服器端嗎,瀏覽器都會將 Cookie 資訊傳送給伺服器端,伺服器端根據 Cookie 來識別使用者的對談資訊。Cookie 有如下幾個特點:

  • 儲存在使用者端
  • 可以被使用者端修改和刪除
  • 資料比較小,例如使用者基本資訊、購物資訊
  • 可以設定過期時間。

Session 是伺服器端儲存對談資訊,當用戶端請求伺服器端時,伺服器端會被每個使用者建立一個唯一的對談(Session id)標識,並在伺服器端設定和儲存對談資訊,並在後續的請求,可以獲取到對談資訊,主要有如下特點:

  • 儲存在伺服器端,使用者端無法修改和刪除
  • 資料比較大,比如使用者的資訊,登入記錄。
  • 通常依賴 Cookie 和使用者端進行資料交換。

Cookie 和 Session 的主要區別:

  • 儲存位置:Cookie 儲存在使用者端,Session 儲存在伺服器端上。
  • 資料大小:Cookie 通常比較小,Session 通常儲存較大的資料。
  • 安全性:Cookie 可以通過 js 設定和修改,也可能通過抓包工具修改,可以輕易的被修改,Cookie 安全性差,很多瀏覽器也禁用了 Cookie,Cookie 使用也不多。Session 的設定和修改都在伺服器端,安全性相對 Cookie 高很多。

在實際的使用場景上,Cookie 和 Session 也會結合使用,伺服器端使用Session記錄使用者的對談資訊,而將對談資訊儲存在 Cookie 中,這樣可以減少伺服器端的壓力。