JavaWeb的session及其共享技術

1.什麼叫會話

​ 一次會話指的是:就好比打電話,A給B打電話,接通之後,會話開始,直到掛斷電話,該次會話就結束了,而瀏覽器訪問服務器,就跟打電話一樣,瀏覽器A給服務器發送請求,訪問web程序,該次會話就已經接通,其中不管瀏覽器發送多少請求(就相當於接通電話後說話一樣),都視爲一次會話,直到瀏覽器關閉,本次會話結束。

​ 其中注意,一個瀏覽器就相當於一部電話,如果使用火狐瀏覽器,訪問服務器,就是一次會話了,然後打開google瀏覽器,訪問服務器,這是另一個會話,雖然是在同一臺電腦,同一個用戶在訪問,但是,這是兩次不同的會話。

2.引入cookie和session

​ 思考一個問題,一個瀏覽器訪問一個服務器就能建立一個會話,如果別的電腦,都同時訪問該服務器,就會創建很多會話,就拿一些購物網站來說,我們訪問一個購物網站的服務器,會話就被創建了,然後就點擊瀏覽商品,對感興趣的商品就先加入購物車,等待一起付賬,這看起來是很普通的操作,但是想一下,如果有很多別的電腦上的瀏覽器同時也在訪問該購物網站的服務器,跟我們做類似的操作呢?服務器又是怎麼記住用戶,怎麼知道用戶A購買的任何商品都應該放在A的購物車內,不論是用戶A什麼時間購買的,不能放入用戶B或用戶C的購物車內的呢?

​ 這裏我們就用cookie和session兩種會話跟蹤技術來跟蹤整個會話。

3.cookie簡介

3.1.cookie的工作原理

JavaWeb的session及其共享技術
1)首先瀏覽器向服務器發出請求。

2)服務器就會根據需要生成一個Cookie對象,並且把數據保存在該對象內。

3)然後把該Cookie對象放在響應頭,一併發送回瀏覽器。

4)瀏覽器接收服務器響應後,提出該Cookie保存在瀏覽器端。

5)當下一次瀏覽器再次訪問那個服務器,就會把這個Cookie放在請求頭內一併發給服務器。

6) 服務器從請求頭提取出該Cookie,判別裏面的數據,然後作出相應的動作。

3.2.cookie中的常用方法

Cookie cookie=new Cookie(String name,String value) 構造一個cookie對象

response.addCookie(Cookie cookie) 是將一個cookie對象傳入客戶端。

request.getCookies() 得到所有的cookie對象

cookie.getName() 得到此cookie對象的名字

cookie.getValue() 得到對應名稱的cookie的值

cookie.setMaxAge() 設置過期時間

3.3.案例

@WebServlet("/CookieServletDemo1")
public class CookieServletDemo1 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public CookieServletDemo1() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // 創建cookie對象
    // cookie中`存放的數據以鍵值對存在map<String,String> 鍵和值都只能是字符串,不支持中文
    Cookie cookie = new Cookie("username", "zhangsan");
    Cookie cookie1 = new Cookie("password", "1234");
    // 失效時間 以秒爲單位
    cookie.setMaxAge(60 * 60);
    response.addCookie(cookie);
    response.addCookie(cookie1);
  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}
@WebServlet("/CookieServletDemo2")
public class CookieServletDemo2 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public CookieServletDemo2() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    //      從請求頭中獲取cookie信息
    Cookie[] cookies = request.getCookies();
    for(Cookie c:cookies){
      System.out.println(c.getName()+"===="+c.getValue());
    }
  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}

3.4.瀏覽器中查看cookie

不同的瀏覽器略有差別,這裏以谷歌瀏覽器爲例。

F12打開開發者工具 ---點擊Application選項---選中其中的cookie---選擇相應的站點---看到該站點中的所有cookie信息。

3.5.cookie的應用場景

​ cookie的應用場景有很多,最具代表性的當屬網站的記錄用戶賬號和密碼的功能了,大家可能經常看到登錄某某論壇,某某網站時,下面有個選項爲N天內自動登錄,其實這就是cookie的應用。當用戶第一次輸入賬號密碼時給服務器發送請求時,服務器會根據賬號密碼回寫一個字符串cookie,當用戶下次再向該服務器發送登錄請求時,則帶着這個字符串cookie一起去訪問服務器,這時,服務器只需要對比次字符串和數據庫中存儲的字符串是否相同,則可以達到用戶自動登錄功能。

3.6.cookie的侷限性

  • Cookie數量和長度的限制。每個站點最多只能有20條cookie,每個cookie長度不能超過4KB,否則會被截掉。
  • cookie中只能存字符串。且不支持中文
  • cookie不適合保存敏感數據(例如密碼)可見的

4.session

4.1.session的工作原理

JavaWeb的session及其共享技術

1)瀏覽器發出請求到服務器。

2)服務器會根據需求生成Session對象,並且給這個Session對象一個編號,一個編號對應一個Session對象

3)服務器把需要記錄的數據封裝到這個Session對象裏,然後把這個Session對象保存下來。

4)服務器把這個Session對象的編號放到一個Cookie裏,隨着響應發送給瀏覽器

5)瀏覽器接收到這個cookie就會保存下來

6)當下一次瀏覽器再次請求該服務器服務,就會發送該Cookie

7)服務器得到這個Cookie,取出它的內容,它的內容就是一個Session的編號!!!

8)憑藉這個Session編號找到對應的Session對象,然後利用該Session對象把保存的數據取出來!

4.2.session的常用方法

方法 解釋
void setAttribute(String attribute, Object value) 設置Session屬性。value參數可以爲任何Java Object。通常爲Java Bean。value信息不宜過大
String getAttribute(String attribute) 返回Session屬性
void removeAttribute(String attribute) 移除Session屬性
String getId() 返回Session的ID。該ID由服務器自動創建,不會重複
long getCreationTime() 返回Session的創建日期。
long getLastAccessedTime() 返回Session的最後活躍時間。返回類型爲long
int getMaxInactiveInterval() 返回Session的超時時間。單位爲秒。超過該時間沒有訪問,服務器認爲該Session失效
void setMaxInactiveInterval(int second) 設置Session的超時時間。單位爲秒4.3.

4.3.案例

@WebServlet("/SeesionServletDemo1")
public class SeesionServletDemo1 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public SeesionServletDemo1() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    // 創建session對象
    HttpSession session = request.getSession();
    System.out.println(session.getId());

    session.setAttribute("name", "zhangsan");

    session.setAttribute("student", new Student(1, "zhangsan", 12));
    Student stu = (Student) session.getAttribute("student");

    stu.setName("lisi");

    // 設置過期時間 單位是秒
    //      session.setMaxInactiveInterval(2);
    // 直接銷燬session  註銷登錄
    //      session.invalidate();

  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}
public class Student {

  private Integer id;
  private String name;
  private Integer age;
  public Integer getId() {
    return id;
  }
  public void setId(Integer id) {
    this.id = id;
  }
  public String getName() {
    return name;
  }
  public void setName(String name) {
    this.name = name;
  }
  public Integer getAge() {
    return age;
  }
  public void setAge(Integer age) {
    this.age = age;
  }
  public Student(Integer id, String name, Integer age) {
    super();
    this.id = id;
    this.name = name;
    this.age = age;
  }
  public Student() {
    super();
    // TODO Auto-generated constructor stub
  }
}
@WebServlet("/SeesionServletDemo2")
public class SeesionServletDemo2 extends HttpServlet {
  private static final long serialVersionUID = 1L;

  /**
     * @see HttpServlet#HttpServlet()
     */
  public SeesionServletDemo2() {
    super();
    // TODO Auto-generated constructor stub
  }

  /**
     * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doGet(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {

    // 創建session對象
    HttpSession session = request.getSession();

    System.out.println(session.getAttribute("name"));

    Student stu = (Student) session.getAttribute("student");
    System.out.println(stu.getName());

  }

  /**
     * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
     *      response)
     */
  protected void doPost(HttpServletRequest request, HttpServletResponse response)
    throws ServletException, IOException {
    // TODO Auto-generated method stub
    doGet(request, response);
  }

}

4.4.session的生命週期

session對象生命週期:

  • session對象什麼創建?
    • 執行request.getSession()方法時
  • session對象什麼銷燬?
    • 默認情況下,session對象在30分鐘之後服務器自動銷燬。
    • 手動設置session有效時長
    • void setMaxInactiveInterval(int interval) -以秒爲單位。
    • 手動銷燬
    • void invalidate()

4.5.session在一次會話結束後消失的原因

​ 由於session的使用需要依賴cookie,cookie每次從瀏覽器端傳輸session的id到後臺,然後查找對應編號的session進行使用,但由於此時的cookie默認的失效時間是一次會話,當一次會話結束後,存放id的cookie對象就消失了,下一次會話訪問時就會生成新的id,那存儲在原來的session對象中的數據就無法找到了。

4.6.瀏覽器禁用cookie能否使用session

可以,但需要手動拼接id傳過去,例如

http://localhost:8080/day06/session.jsp;jsessionid=AE62ECBAAD2CA16DA6AEBF1D1527CD45

jsessionid指的就是session對應的id

4.7.session共享

4.7.1.基於數據庫的Session共享

首選當然是大名鼎鼎的Mysql數據庫,並且建議使用內存表Heap,提高session操作的讀寫效率。這個方案的實用性比較強,相信大家普遍在使用,它的缺點在於session的併發讀寫能力取決於Mysql數據庫的性能,同時需要自己實現session淘汰邏輯,以便定時從數據表中更新、刪除 session記錄,當併發過高時容易出現表鎖,雖然我們可以選擇行級鎖的表引擎,但不得不否認使用數據庫存儲Session還是有些殺雞用牛刀的架勢。

4.7.2.基於Cookie的Session共享

​ 這個方案我們可能比較陌生,但它在大型網站中還是比較普遍被使用。原理是將全站用戶的Session信息加密、序列化後以Cookie的方式, 統一種植在根域名下(如:.host.com),利用瀏覽器訪問該根域名下的所有二級域名站點時,會傳遞與之域名對應的所有Cookie內容的特性,從而實現 用戶的Cookie化Session 在多服務間的共享訪問。

  這個方案的優點無需額外的服務器資源;缺點是由於受http協議頭信心長度的限制,僅能夠存儲小部分的用戶信息,同時Cookie化的 Session內容需要進行安全加解密(如:採用DES、RSA等進行明文加解密;再由MD5、SHA-1等算法進行防僞認證),另外它也會佔用一定的帶寬資源,因爲瀏覽器會在請求當前域名下任何資源時將本地Cookie附加在http頭中傳遞到服務器。

4.7.3.基於Memcache的Session共享

 Memcache由於是一款基於Libevent多路異步I/O技術的內存共享系統,簡單的Key + Value數據存儲模式使得代碼邏輯小巧高效,因此在併發處理能力上佔據了絕對優勢,目前本人所經歷的項目達到2000/秒 平均查詢,並且服務器CPU消耗依然不到10%。

  另外值得一提的是Memcache的內存hash表所特有的Expires數據過期淘汰機制,正好和Session的過期機制不謀而合,降低了 過期Session數據刪除的代碼複雜度,對比“基於數據庫的存儲方案”,僅這塊邏輯就給數據表產生巨大的查詢壓力。

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