從一開始迷糊到現在的session和cookie

如果你說你不會session和cookie,學java的人會對你嗤之以鼻,因爲那是基礎的技術,是面試中簡單的問題,在網上有大量資料。但是,這並不是一個簡單的問題。因爲session這個詞在被濫用,我讀很多文檔時都碰到過session,有時候人們說它是一次會話(會話又是什麼?),有時說它是jsp的一個默認作用域,有時又說它是瀏覽器打開到關閉的一個情況……

關鍵的問題是,當我們在談session與cookie時,它指的是什麼?

session與cookie刨根問底

RFC2109

This document describes a way to create stateful sessions with HTTP requests and responses. Currently, HTTP servers respond to each client request without relating that request to previous or
subsequent requests; the technique allows clients and servers that wish to exchange state information to place HTTP requests and responses within a larger context, which we term a “session”. This context might be used to create, for example, a “shopping cart”, in which user selections can be aggregated before purchase, or a magazine browsing system, in which a user’s previous reading affects which offerings are presented.

文檔說的很清楚,爲了解決http協議的無狀態性,我們需要一種技術,這種技術能把http request和http response置於一種更大的上下文中,我們把它叫做session

There are, of course, many different potential contexts and thus many different potential types of session. The designers’ paradigm for sessions created by the exchange of cookies has these key attributes:

  1. Each session has a beginning and an end.
  2. Each session is relatively short-lived.
  3. Either the user agent or the origin server may terminate a session.
  4. The session is implicit in the exchange of state information.

由於上下文有很多種,因此session也有很多種。由cookie來實現的session有幾個特點:

  • 每個session有開始有結束
  • 每個session相對短命
  • 客戶端和服務端都能終結一個session
  • session在信息交換中是隱式存在的

The origin server initiates a session, if it so desires. (Note that “session” here does not refer to a persistent network connection but to a logical session created from HTTP requests and responses. The presence or absence of a persistent connection should have no effect on the use of cookie-derived sessions). To initiate a session, the origin server returns an extra response header to the client, Set-Cookie.

它說服務端初始化一個session,然後我們一直講的session是一個邏輯概念,而大家平時講的session是一種持續的客戶端和服務端的網絡連接。不管有沒有這種連接,都不會影響cookie-derived的session的使用。

A user agent returns a Cookie request header (see below) to the origin server if it chooses to continue a session. The origin server may ignore it or use it to determine the current state of the session. It may send back to the client a Set-Cookie response heade with the same or different information, or it may send no Set-Cookie header at all. The origin server effectively ends a session by sending the client a Set-Cookie header with Max-Age=0.

origin server把cookie放在response header中,user agent回的cookie放在request header中。

語法和解析的細節我就不說了,大家可以自己去查閱文檔。


它這裏舉了一個很好的例子:

    1.  User Agent -> Server

         POST /acme/login HTTP/1.1
         [form data]

         User identifies self via a form.

用戶登錄。


     2.  Server -> User Agent

         HTTP/1.1 200 OK
         Set-Cookie: Customer="WILE_E_COYOTE"; Version="1"; Path="/acme"

         Cookie reflects user's identity.

服務端把cookie放在header中。

    3.  User Agent -> Server

         POST /acme/pickitem HTTP/1.1
         Cookie: $Version="1"; Customer="WILE_E_COYOTE"; $Path="/acme"
         [form data]

         User selects an item for "shopping basket."

用戶選了一件商品。user agent回的時候在VersionPath前都加了$,因爲origin server在解析的時候會從左往右讀,讀到不是$開頭的信息就找到了該cookie的name(這裏是Customer)。

 4.  Server -> User Agent

         HTTP/1.1 200 OK
         Set-Cookie: Part_Number="Rocket_Launcher_0001"; Version="1";
                 Path="/acme"

         Shopping basket contains an item.

購物車裏放了商品。

   5.  User Agent -> Server

         POST /acme/shipping HTTP/1.1
         Cookie: $Version="1";
                 Customer="WILE_E_COYOTE"; $Path="/acme";
                 Part_Number="Rocket_Launcher_0001"; $Path="/acme"
         [form data]

         User selects shipping method from form.

用戶選擇支付手段。

6.  Server -> User Agent

         HTTP/1.1 200 OK
         Set-Cookie: Shipping="FedEx"; Version="1"; Path="/acme"

         New cookie reflects shipping method.

header中新添加的cookie反映了使用的支付手段。


     7.  User Agent -> Server

         POST /acme/process HTTP/1.1
         Cookie: $Version="1";
                 Customer="WILE_E_COYOTE"; $Path="/acme";
                 Part_Number="Rocket_Launcher_0001"; $Path="/acme";
                 Shipping="FedEx"; $Path="/acme"
         [form data]

         User chooses to process order.

用戶選擇處理訂單。

    8.  Server -> User Agent

         HTTP/1.1 200 OK

         Transaction is complete.

成功,交易結束。

這個例子完美展示瞭如何通過cookie實現服務端和客戶端的交流。


Cookie

上面的是規範,tomcat怎麼實現的呢?

javax.servlet.http.Cookie的文檔:

/**
 * Creates a cookie, a small amount of information sent by a servlet to a Web
 * browser, saved by the browser, and later sent back to the server. A cookie's
 * value can uniquely identify a client, so cookies are commonly used for
 * session management.
 * <p>
 * A cookie has a name, a single value, and optional attributes such as a
 * comment, path and domain qualifiers, a maximum age, and a version number.
 * Some Web browsers have bugs in how they handle the optional attributes, so
 * use them sparingly to improve the interoperability of your servlets.
 * <p>
 * The servlet sends cookies to the browser by using the
 * {@link HttpServletResponse#addCookie} method, which adds fields to HTTP
 * response headers to send cookies to the browser, one at a time. The browser
 * is expected to support 20 cookies for each Web server, 300 cookies total, and
 * may limit cookie size to 4 KB each.
 * <p>
 * The browser returns cookies to the servlet by adding fields to HTTP request
 * headers. Cookies can be retrieved from a request by using the
 * {@link HttpServletRequest#getCookies} method. Several cookies might have the
 * same name but different path attributes.
 * <p>
 * Cookies affect the caching of the Web pages that use them. HTTP 1.0 does not
 * cache pages that use cookies created with this class. This class does not
 * support the cache control defined with HTTP 1.1.
 * <p>
 * This class supports both the RFC 2109 and the RFC 6265 specifications.
 * By default, cookies are created using RFC 6265.
 */

因爲cookie能夠用來定位唯一確定的client,所以被用作session管理。

cookie既然能實現客戶端和服務端的交流,那爲什麼要出現其他session技術呢?

因爲cookie有缺點。

由於cookie暴露在了瀏覽器,所以不安全,而且容量小。


JSESSIONID

所以我們要用到HttpSession

public interface HttpSession
Provides a way to identify a user across more than one page request or visit to a Web site and to store information about that user.
The servlet container uses this interface to create a session between an HTTP client and an HTTP server. The session persists for a specified time period, across more than one connection or page request from the user. A session usually corresponds to one user, who may visit a site many times. The server can maintain a session in many ways such as using cookies or rewriting URLs.

This interface allows servlets to
1.View and manipulate information about a session, such as the session identifier, creation time, and last accessed time
2.Bind objects to sessions, allowing user information to persist across multiple user connections

HttpSession與用戶一一對應。因此當一個用戶登錄JD之後,就不用在購物頁面、支付頁面重複登錄了。

HttpSession在這方面與Cookie一模一樣,它們都是session的具體實現。

至於關掉瀏覽器後,cookie是否還在,session是否還在,這個都可以自己寫代碼試一下。

現在的問題是,HttpSession怎麼與一個client一一對應呢?

我們在HttpSession session = request.getSession();上打一個斷點,觀察瀏覽器第一次訪問時的情況。


一直get。像getBean一樣。


create。

這裏的manager也是tomcat中的頂級管理接口。


創建session對象。

注意這裏:

generateSessionId產生了sessionID,就是那一長串的32個字符的字符串。

服務端創建的session對象:


這個StandardSession就是HttpSessin的一個實現類。

服務端自己創建session之後,還要做一個工作:


他要在這個session的基礎之上創建一個cookie。


這個cookie的value就是sessionID的值。

那麼這個特殊的cookie的key是多少呢?


那就是神祕的JSESSIONID

也就是說,當瀏覽器第一次訪問服務器的時候,服務端會生成一個sessionID,然後以JSESSIONID作爲key,以sessionID的值作爲value創建一個cookie,然後添加到header中:


於是,瀏覽器的JSESSIONID的value就和服務端的sessionID對應了。

我們可以說,HttpSession是建立在Cookie之上的。

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