天天看點

cookie和session詳解狀态管理-Cookie

1.1. 為什麼需要狀态管理

  Web應用程式使用HTTP協定作為傳輸資料的标準協定,而HTTP協定是無狀态協定,即一次請求對應一次響應,響應結束後連接配接即斷開,同一個使用者的不同請求對于伺服器端來講并不會認為這兩個請求有什麼關聯性,并不會以此區分不同的用戶端。但實際情況中還是需要伺服器端能夠區分不同的用戶端以及記錄與用戶端相關的一些資料,是以狀态管理能夠做到不同用戶端的身份識别。

1.2. 什麼是狀态管理

  将用戶端與伺服器之間多次互動當做一個整體來看待,并且将多次互動中涉及的資料儲存下來,提供給後續的互動進行資料的管理即狀态管理。

  這裡的狀态指的是目前的資料,管理指的是在這個多次互動的過程中對資料的存儲、修改、删除。

  生活中很多與狀态管理類似的案例。如洗車卡記錄洗車次數就是很典型的狀态管理。洗車卡可以是一張記錄簡單次數的标示,車主每次攜帶卡片洗車後由商家修改,車主即可帶走這張記錄資料的卡片,商家不會儲存任何資料,客戶自己負責攜帶需要維護的資料。還有一種處理方式就是商家隻給客戶一個卡号,每次客戶來洗車時自己不會記錄洗車次數,隻要報上卡号,商家就會從系統中找到與卡号對應的資料,修改後仍然是商家儲存,客戶帶走的隻是一個卡号這個标示。

  以上兩種模式都能實作洗車次數的記錄,也就是資料的管理,隻是各有利弊,程式中的狀态管理與這個案例都采用了同樣的處理原理。

1.3. 狀态管理兩種常見模式

  狀态管理的過程中重要的是資料的儲存,隻有存下來的資料才能在多次互動中起到記錄的作用,是以可以按照管理的資料的存儲方式和位置的不同來區分狀态管理的模式。

  如果将資料存儲在用戶端,每次向伺服器端發請求時都将存在用戶端的資料随着請求發送到伺服器端,修改後再發回到用戶端儲存的這種模式叫做Cookie。

  如果将資料存儲在伺服器端,并且為這組資料标示一個編号,隻将編号發回給用戶端。當用戶端向伺服器發送請求時隻需要将這個編号發過來,伺服器端按照這個編号找到對應的資料進行管理的這種模式叫做Session——會話。

  由于Cookie資料是由用戶端來儲存和攜帶的,是以稱之為用戶端技術。

  建立一個cookie,cookie是servlet發送到web浏覽器的少量資訊,這些資訊由浏覽器儲存,然後發送回伺服器。cookie的值可以唯一辨別用戶端,是以cookie常用于會話管理。

  一個cookie擁有一個名稱、一個值和一些可選屬性,比如注釋、路徑和域限定符。最大生存時間和版本号。一些浏覽器在處理可選屬性方面存在bug,是以有節制地使用這些屬性可提高servlet的互操作性

  servlet 通過使用 HttpServletResponse#addCookie 方法将 cookie 發送到浏覽器,該方法将字段添加到** HTTP 響應頭,以便一次一個地将 cookie 發送到浏覽器。浏覽器應該支援每台 Web 伺服器有 20 個 cookie,總共有 300 個 cookie,并且可能将每個 **cookie 的大小限定為 4 KB。

  浏覽器通過向 HTTP 請求頭添加字段将 cookie 傳回給 servlet。可使用 HttpServletRequest#getCookies 方法從請求中擷取 cookie。一些 cookie 可能有相同的名稱,但卻有不同的路徑屬性。

  cookie 影響使用它們的 Web 頁面的緩存。HTTP 1.0 不會緩存那些使用通過此類建立的 cookie 的頁面。此類不支援 HTTP 1.1 中定義的緩存控件。

name:名稱不能唯一确定一個Cookie。路徑可能不同。

value:不能存中文。

path:預設值是寫Cookie的那個程式的通路路徑

例子:

 path就是:/cookie/servlet 看目前建立cookie的資源(servlet)檔案路徑

 用戶端在通路伺服器另外資源時,根據通路的路徑來決定是否帶着Cookie到伺服器

 目前通路的路徑如果是以cookie的path開頭的路徑,浏覽器就帶。否則不帶。

Cookie c = new Cookie(“uname”,“jack”);

c.setPath(“/test”);

response.addCookie(c);

* maxAge*:cookie的緩存時間。預設是-1(預設存在浏覽器的記憶體中)。機關是秒。

負數:cookie的資料存在浏覽器緩存中

0:删除。路徑要保持一緻,否則可能删錯人。

正數:緩存(持久化到磁盤上)的時間

public String getName()

  傳回 cookie 的名稱。名稱在建立之後不得更改。

public void setValue(String newValue)

  在建立 cookie 之後将新值配置設定給 cookie。如果使用二進制值,則可能需要使用 BASE64 編碼。

  對于 Version 0 cookie,值不應包含空格、方括号、圓括号、等号、逗号、雙引号、斜杠、問号、at 符号、冒号和分号。空值在所有浏覽器上的行為不一定相同。

public void setPath(String uri)

  指定用戶端應該傳回 cookie 的路徑。

cookie 對于指定目錄中的所有頁面及該目錄子目錄中的所有頁面都是可見的。cookie 的路徑必須包括設定 cookie 的 servlet,例如 /catalog,它使 cookie 對于伺服器上 /catalog 下的所有目錄都是可見的。

public String getPath()

  傳回浏覽器将此 cookie 傳回到的伺服器上的路徑。cookie 對于伺服器上的所有子路徑都是可見的。

public void setMaxAge(int expiry)

  設定 cookie 的最大生存時間,以秒為機關。

  正值表示 cookie 将在經過該值表示的秒數後過期。注意,該值是 cookie 過期的最大 生存時間,不是 cookie 的目前生存時間。

  負值意味着 cookie 不會被持久存儲,将在 Web 浏覽器退出時删除。0 值會導緻删除 cookie。

  cookie隻能儲存合法的Ascii字元。如果要儲存中文,需要将中文轉換成合法的Ascii字元,及編碼

  cookie解碼

  編碼後的Cookie為了看到實際的中文,需要還原後再顯示

  Cookie由于存放的位置在用戶端,是以可以通過修改設定被使用者禁止。Cookie本質就是一小段文本,一小段說的是隻能儲存少量資料,長度是有限制的,一般為4kb左右。文本說的是隻能儲存字元串,不能保留複雜的對象類型資料。

  作為網絡中傳輸的内容,Cookie安全性很低,非常容易通過截取資料包來擷取,在沒有加密的情況下不要用于存放敏感資料。

  就算是能夠存放的長度很短,但作為網絡中傳輸的内容也會增加網絡的傳輸量影響帶寬。在伺服器處理大量請求的時候,Cookie的傳遞無疑會增加網絡的負載量。

 HttpSession(全名):

  它也是一個域對象: session servletContext request

  同一個會話下,可以使一個應用的多個資源共享資料

  cookie用戶端技術,隻能存字元串。HttpSession伺服器端的技術,它可以存對象

  工作原理:浏覽器第一次通路伺服器時,伺服器會為該用戶端配置設定一塊對象空間,并且使用不同的SID來進行辨別,該辨別SID會随着響應發回到用戶端,且被儲存在記憶體中。當同一個用戶端再次發送請求時,辨別也會被同時發送到伺服器端,而伺服器判斷要使用哪一個Session對象内的資料時,就會根據用戶端發來的這個SID來進行查找。

  獲得session有兩種情況,要麼請求中沒有SID,則需要建立;要麼請求中包含一個SID,根據SID去找對應的對象,但也存在找到找不到的可能。

  但不管哪種情況都依賴于請求中的這個唯一辨別,雖然對于程式設計人員來講不需要去檢視這個基本不會重複、編号很長的辨別,但要想擷取到與用戶端關聯的這個session對象一定要基于請求,

  是以在Request類型的API中包含擷取到session對象的方法,代碼如下所示:

  使用第一種擷取session對象的方法時,

  flag = true:先從請求中找找看是否有SID,沒有會建立新Session對象,有*SID會查找與編号對應的對象,找到比對的對象則傳回,找不到SID對應的對象時則會建立新Session對象。是以,填寫true就一定會得到一個Session對象*。

  flag= false:不存在SID以及按照SID找不到Session對象時都會傳回null,隻有根據SID找到對應的對象時會傳回具體的Session對象。是以,填寫false隻會傳回已經存在并且與SID比對上了的Session對象。

  request.getSession()方法不填寫參數時等同于填寫true,提供該方法主要是為了書寫代碼時更友善,大多數情況下還是希望能夠傳回一個Session對象的。

  Session作為伺服器端為各用戶端儲存互動資料的一種方式,采用name-value對的形式來區分每一組資料。

Session設定屬性值

擷取綁定資料或移除綁定資料的代碼如下:

  void session.getAttribute(String name);

  void session.removeAttribute(String name);

删除Session對象

如果用戶端想删除SID對應的Session對象時,可以使用Session對象的如下方法:

  void invalidate()

  該方法會使得伺服器端與該用戶端對應的S**ession對象不再被Session容器管理**,進入到垃圾回收的狀态。對于這種立即删除Session對象的操作主要應用于不再需要身份識别的情況下,如登出操作。

  Session會以對象的形式占用伺服器端的記憶體,過多的以及長期的消耗記憶體會降低伺服器端的運作效率,是以Session對象存在于記憶體中時會有預設的時間限制,一旦Session對象存在的時間超過了這個預設的時間限制則認為是Session逾時,Session會失效,不能再繼續通路。

  Web伺服器預設的逾時時間設定一般是30分鐘。

有兩種方式可以修改Session的預設時間限制,程式設計式和聲明式。

程式設計式:

  void setMaxInactiveInterval(int seconds)

聲明式(再web.xml聲明):

-   使用聲明式來修改預設時間,那麼該應用建立的所有Session對象的生命周期都會應用這個規定的時間,機關為分鐘。

-   使用程式設計式來修改預設時間隻會針對調用該方法的Session對象應用這一原則,不會影響到其他對象,是以更靈活。通常在需要特殊設定時使用這種方式。時間機關是秒,與聲明式的時間機關不同。

  Session對象的查找依靠的是SID,而這個ID儲存在用戶端時是以Cookie的形式儲存的。一旦浏覽器禁用Cookie,那麼SID無法儲存,Session對象将不再能使用。

  為了在禁用Cookie後依然能使用Session,那麼将使用其他的存儲方法來完成SID的儲存。URL位址在網絡傳輸過程中不僅僅能夠起到标示位址的作用,還可以在其後攜帶一些較短的資料,SID就可以通過URL來實作儲存,及URL重寫。

  浏覽器在通路伺服器的某個位址時,會使用一個改寫過的位址,即在原有位址後追加SessionID,這種重新定義URL内容的方式叫做URL重寫。

如何實作URL重寫

 生成連結位址和表單送出時,使用如下代碼:

 <a href=”<%=response.encodeURL(String url)>”>連結位址

如果是重定向,使用如下代碼代替response.sendRedirect()

  response.encodeRedirectURL(String url);

Cookie 和Session的優缺點

Session對象的資料由于儲存在伺服器端,并不在網絡中進行傳輸,是以安全一些,并且能夠儲存的資料類型更豐富,同時Session也能夠儲存更多的資料,Cookie隻能儲存大約4kb的字元串。

Session的安全性是以犧牲伺服器資源為代價的,如果使用者量過大,會嚴重影響伺服器的性能。Cookie資料存在浏覽器中,容易被篡改,安全性差,但節約伺服器的記憶體。是以重要資料存儲在session中,一般資料存在cookie中。