Cookie和Session的區別

 

具體來講cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在服務器端保持狀態的方案。同時咱們也看到,因爲採用服務器端保持狀態的方案在客戶端也須要保存一個標識,因此session機制可能須要藉助於cookie機制來達到保存標識的目的,但實際上它還有其餘選擇。

cookie機制。正統的cookie分發是經過擴展HTTP協議來實現的,服務器經過在HTTP的響應頭中加上一行特殊的指示以提示瀏覽器按照指示生成相應的cookie。然而純粹的客戶端腳本如JavaScript或者VBScript也能夠生成cookie。而cookie的使用是由瀏覽器按照必定的原則在後臺自動發送給服務器的。瀏覽器檢查全部存儲的cookie,若是某個cookie所聲明的做用範圍大於等於將要請求的資源所在的位置,則把該cookie附在請求資源的HTTP請求頭上發送給服務器。
cookie的內容主要包括:名字,值,過時時間,路徑和域。路徑與域一塊兒構成cookie的做用範圍。若不設置過時時間,則表示這個cookie的生命期爲瀏覽器會話期間,關閉瀏覽器窗口,cookie就消失。這種生命期爲瀏覽器會話期的cookie被稱爲會話cookie。會話cookie通常不存儲在硬盤上而是保存在內存裏,固然這種行爲並非規範規定的。若設置了過時時間,瀏覽器就會把cookie保存到硬盤上,關閉後再次打開瀏覽器,這些cookie仍然有效直到超過設定的過時時間。存儲在硬盤上的cookie能夠在不一樣的瀏覽器進程間共享,好比兩個IE窗口。而對於保存在內存裏的cookie,不一樣的瀏覽器有不一樣的處理方式
session機制。session機制是一種服務器端的機制,服務器使用一種相似於散列表的結構(也可能就是使用散列表)來保存信息。

當程序須要爲某個客戶端的請求建立一個session時,服務器首先檢查這個客戶端的請求裏是否已包含了一個session標識(稱爲session id),若是已包含則說明之前已經爲此客戶端建立過session,服務器就按照session id把這個session檢索出來使用(檢索不到,會新建一個),若是客戶端請求不包含session id,則爲此客戶端建立一個session而且生成一個與此session相關聯的session id,session id的值應該是一個既不會重複,又不容易被找到規律以仿造的字符串,這個session id將被在本次響應中返回給客戶端保存。
保存這個session id的方式能夠採用cookie,這樣在交互過程當中瀏覽器能夠自動的按照規則把這個標識發揮給服務器。通常這個cookie的名字都是相似於SEEESIONID。但cookie能夠被人爲的禁止,則必須有其餘機制以便在cookie被禁止時仍然可以把session id傳遞迴服務器。
常常被使用的一種技術叫作URL重寫,就是把session id直接附加在URL路徑的後面。還有一種技術叫作表單隱藏字段。就是服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時可以把session id傳遞迴服務器。好比:
<form name="testform" action="/xxx">
<input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764">
<input type="text">
</form>
實際上這種技術能夠簡單的用對action應用URL重寫來代替。

 

 

 

 

 

1、cookie機制和session機制的區別
  具體來講cookie機制採用的是在客戶端保持狀態的方案,而session機制採用的是在服務器端保持狀態的方案。
  同時咱們也看到,因爲在服務器端保持狀態的方案在客戶端也須要保存一個標識,因此session機制可能須要藉助於cookie機制來達到保存標識的目的,但實際上還有其餘選擇。
2、會話cookie和持久cookie的區別
  若是不設置過時時間,則表示這個cookie生命週期爲瀏覽器會話期間,只要關閉瀏覽器窗口,cookie就消失了。這種生命期爲瀏覽會話期的cookie被稱爲會話cookie。會話cookie通常不保存在硬盤上而是保存在內存裏。
  若是設置了過時時間,瀏覽器就會把cookie保存到硬盤上,關閉後再次打開瀏覽器,這些cookie依然有效直到超過設定的過時時間。
  存儲在硬盤上的cookie能夠在不一樣的瀏覽器進程間共享,好比兩個IE窗口。而對於保存在內存的cookie,不一樣的瀏覽器有不一樣的處理方式。
3、如何利用實現自動登陸
  當用戶在某個網站註冊後,就會收到一個唯一用戶ID的cookie。客戶後來從新鏈接時,這個用戶ID會自動返回,服務器對它進行檢查,肯定它是否爲註冊用戶且選擇了自動登陸,從而使用戶無需給出明確的用戶名和密碼,就能夠訪問服務器上的資源。
4、如何根據用戶的愛好定製站點
  網站可使用cookie記錄用戶的意願。對於簡單的設置,網站能夠直接將頁面的設置存儲在cookie中完成定製。然而對於更復雜的定製,網站只需僅將一個唯一的標識符發送給用戶,由服務器端的數據庫存儲每一個標識符對應的頁面設置。
5、cookie的發送
1.建立Cookie對象
2.設置最大時效
3.將Cookie放入到HTTP響應報頭
  若是你建立了一個cookie,並將他發送到瀏覽器,默認狀況下它是一個會話級別的cookie:存儲在瀏覽器的內存中,用戶退出瀏覽器以後被刪除。 若是你但願瀏覽器將該cookie存儲在磁盤上,則須要使用maxAge,並給出一個以秒爲單位的時間。將最大時效設爲0則是命令瀏覽器刪除該 cookie。
  發送cookie須要使用HttpServletResponse的addCookie方法,將cookie插入到一個 Set-Cookie HTTP請求報頭中。因爲這個方法並不修改任何以前指定的Set-Cookie報頭,而是建立新的報頭,所以咱們將這個方法稱爲是addCookie,而非setCookie。一樣要記住響應報頭必須在任何文檔內容發送到客戶端以前設置。
6、cookie的讀取
1.調用request.getCookie
  要獲取有瀏覽器發送來的cookie,須要調用HttpServletRequest的getCookies方法,這個調用返回Cookie對象的數組,對應由HTTP請求中Cookie報頭輸入的值。
2.對數組進行循環,調用每一個cookie的getName方法,直到找到感興趣的cookie爲止
  cookie與你的主機(域)相關,而非你的servlet或JSP頁面。於是,儘管你的servlet可能只發送了單個cookie,你也可能會獲得許多不相關的cookie。
例如:
  String cookieName = 「userID」;
Cookie cookies[] = request.getCookies();
if (cookies!=null){
for(int i=0;i
 
javascript

Cookie cookie = cookies[i];
if (cookieName.equals(cookie.getName())){
doSomethingWith(cookie.getValue());
}
}
}
7、如何使用cookie檢測初訪者
A.調用HttpServletRequest.getCookies()獲取Cookie數組
B.在循環中檢索指定名字的cookie是否存在以及對應的值是否正確
C.若是是則退出循環並設置區別標識
D.根據區別標識判斷用戶是否爲初訪者從而進行不一樣的操做
8、使用cookie檢測初訪者的常見錯誤
  不能僅僅由於cookie數組中不存在在特定的數據項就認爲用戶是個初訪者。若是cookie數組爲null,客戶多是一個初訪者,也多是因爲用戶將cookie刪除或禁用形成的結果。
  可是,若是數組非null,也不過是顯示客戶曾經到過你的網站或域,並不能說明他們曾經訪問過你的servlet。其它servlet、JSP頁面以及非Java Web應用均可以設置cookie,依據路徑的設置,其中的任何cookie都有可能返回給用戶的瀏覽器。
  正確的作法是判斷cookie數組是否爲空且是否存在指定的Cookie對象且值正確。
9、使用cookie屬性的注意問題
  屬性是從服務器發送到瀏覽器的報頭的一部分;但它們不屬於由瀏覽器返回給服務器的報頭。 
  所以除了名稱和值以外,cookie屬性只適用於從服務器輸出到客戶端的cookie;服務器端來自於瀏覽器的cookie並無設置這些屬性。 
  於是不要指望經過request.getCookies獲得的cookie中可使用這個屬性。這意味着,你不能僅僅經過設置cookie的最大時 效,發出它,在隨後的輸入數組中查找適當的cookie,讀取它的值,修改它並將它存回Cookie,從而實現不斷改變的cookie值。
10、如何使用cookie記錄各個用戶的訪問計數
1.獲取cookie數組中專門用於統計用戶訪問次數的cookie的值
2.將值轉換成int型
3.將值加1並用原來的名稱從新建立一個Cookie對象
4.從新設置最大時效
5.將新的cookie輸出
11、session在不一樣環境下的不一樣含義
  session,中文常常翻譯爲會話,其原本的含義是指善始善終的一系列動做/消息,好比打電話是從拿起電話撥號到掛斷電話這中間的一系列過程能夠稱之爲一個session。
  然而當session一詞與網絡協議相關聯時,它又每每隱含了「面向鏈接」和/或「保持狀態」這樣兩個含義。
  session在Web開發環境下的語義又有了新的擴展,它的含義是指一類用來在客戶端與服務器端之間保持狀態的解決方案。有時候Session也用來指這種解決方案的存儲結構。
12、session的機制
  session機制是一種服務器端的機制,服務器使用一種相似於散列表的結構(也可能就是使用散列表)來保存信息。
  但程序須要爲某個客戶端的請求建立一個session的時候,服務器首先檢查這個客戶端的請求裏是否包含了一個session標識-稱爲session id,若是已經包含一個session id則說明之前已經爲此客戶建立過session,服務器就按照session id把這個session檢索出來使用(若是檢索不到,可能會新建一個,這種狀況可能出如今服務端已經刪除了該用戶對應的session對象,但用戶人爲地在請求的URL後面附加上一個JSESSION的參數)。
  若是客戶請求不包含session id,則爲此客戶建立一個session而且生成一個與此session相關聯的session id,這個session id將在本次響應中返回給客戶端保存。
十3、保存session id的幾種方式
A.保存session id的方式能夠採用cookie,這樣在交互過程當中瀏覽器能夠自動的按照規則把這個標識發送給服務器。
B.因爲cookie能夠被人爲的禁止,必須有其它的機制以便在cookie被禁止時仍然可以把session id傳遞迴服務器,常常採用的一種技術叫作URL重寫,就是把session id附加在URL路徑的後面,附加的方式也有兩種,一種是做爲URL路徑的附加信息,另外一種是做爲查詢字符串附加在URL後面。網絡在整個交互過程當中始終保持狀態,就必須在每一個客戶端可能請求的路徑後面都包含這個session id。
C.另外一種技術叫作表單隱藏字段。就是服務器會自動修改表單,添加一個隱藏字段,以便在表單提交時可以把session id傳遞迴服務器。
十4、session何時被建立
  一個常見的錯誤是覺得session在有客戶端訪問時就被建立,然而事實是直到某server端程序(如Servlet)調用HttpServletRequest.getSession(true)這樣的語句時纔會被建立。
十5、session什麼時候被刪除
session在下列狀況下被刪除:
A.程序調用HttpSession.invalidate()
B.距離上一次收到客戶端發送的session id時間間隔超過了session的最大有效時間
C.服務器進程被中止
  再次注意關閉瀏覽器只會使存儲在客戶端瀏覽器內存中的session cookie失效,不會使服務器端的session對象失效。
十6、URL重寫有什麼缺點
  對全部的URL使用URL重寫,包括超連接,form的action,和重定向的URL。每一個引用你的站點的URL,以及那些返回給用戶的URL(即便經過間接手段,好比服務器重定向中的Location字段)都要添加額外的信息。
  這意味着在你的站點上不能有任何靜態的HTML頁面(至少靜態頁面中不能有任何連接到站點動態頁面的連接)。所以,每一個頁面都必須使用servlet或 JSP動態生成。即便全部的頁面都動態生成,若是用戶離開了會話並經過書籤或連接再次回來,會話的信息都會丟失,由於存儲下來的連接含有錯誤的標識信息-該URL後面的SESSION ID已通過期了。  
十7、使用隱藏的表單域有什麼缺點
僅當每一個頁面都是有表單提交而動態生成時,才能使用這種方法。單擊常規的 超文本連接並不產生表單提交,所以隱藏的表單域不能支持一般的會話跟蹤,只能用於一系列特定的操做中,好比在線商店的結帳過程
十8、會話跟蹤的基本步驟
1.訪問與當前請求相關的會話對象
2.查找與會話相關的信息
3.存儲會話信息
4.廢棄會話數據
十9、getSession()/getSession(true)、getSession(false)的區別
getSession()/getSession(true):當session存在時返回該session,不然新建一個session並返回該對象
getSession(false):當session存在時返回該session,不然不會新建session,返回null
二10、如何將信息與會話關聯起來
  setAttribute會替換任何以前設定的值;若是想要在不提供任何代替的狀況下移除某個值,則應使用removeAttribute。這個方法會觸發全部實現了HttpSessionBindingListener接口的值的valueUnbound方法。
二11、會話屬性的類型有什麼限制嗎
  一般會話屬性的類型只要是Object就能夠了。除了null或基本類型,如int,double,boolean。
  若是要使用基本類型的值做爲屬性,必須將其轉換爲相應的封裝類對象
二12、如何廢棄會話數據
A.只移除本身編寫的servlet建立的數據:
調用removeAttribute(「key」)將指定鍵關聯的值廢棄
B.刪除整個會話(在當前Web應用中):
調用invalidate,將整個會話廢棄掉。這樣作會丟失該用戶的全部會話數據,而非僅僅由咱們servlet或JSP頁面建立的會話數據
C.將用戶從系統中註銷並刪除全部屬於他(或她)的會話
調用logOut,將客戶從Web服務器中註銷,同時廢棄全部與該用戶相關聯的會話(每一個Web應用至多一個)。這個操做有可能影響到服務器上多個不一樣的Web應用。
二十3、使用isNew來判斷用戶是否爲新舊用戶的錯誤作法
  public boolean isNew()方法若是會話還沒有和客戶程序(瀏覽器)發生任何聯繫,則這個方法返回true,這通常是由於會話是新建的,不是由輸入的客戶請求所引發的。
  但若是isNew返回false,只不過是說明他以前曾經訪問該Web應用,並不表明他們曾訪問過咱們的servlet或JSP頁面。
  由於session是與用戶相關的,在用戶以前訪問的每個頁面都有可能建立了會話。所以isNew爲false只能說用戶以前訪問過該Web應用,session能夠是當前頁面建立,也多是由用戶以前訪問過的頁面建立的。
  正確的作法是判斷某個session中是否存在某個特定的key且其value是否正確
二十4、Cookie的過時和Session的超時有什麼區別
  會話的超時由服務器來維護,它不一樣於Cookie的失效日期。首先,會話通常基於駐留內存的cookie不是持續性的cookie,於是也就沒有截至日期。即便截取到JSESSIONID cookie,併爲它設定一個失效日期發送出去。瀏覽器會話和服務器會話也會大相徑庭。
二十5、session cookie和session對象的生命週期是同樣的嗎
  當用戶關閉了瀏覽器雖然session cookie已經消失,但session對象仍然保存在服務器端
二十6、是否只要關閉瀏覽器,session就消失了
  程序通常都是在用戶作log off的時候發個指令去刪除session,然而瀏覽器歷來不會主動在關閉以前通知服務器它將要被關閉,所以服務器根本不會有機會知道瀏覽器已經關閉。服務器會一直保留這個會話對象直到它處於非活動狀態超過設定的間隔爲止。
  之因此會有這種錯誤的認識,是由於大部分session機制都使用會話cookie來保存session id,而關閉瀏覽器後這個session id就消失了,再次鏈接到服務器時也就沒法找到原來的session。
  若是服務器設置的cookie被保存到硬盤上,或者使用某種手段改寫瀏覽器發出的HTTP請求報頭,把原來的session id發送到服務器,則再次打開瀏覽器仍然可以找到原來的session。
  偏偏是因爲關閉瀏覽器不會致使session被刪除,迫使服務器爲session設置了一個失效時間,當距離客戶上一次使用session的時間超過了這個失效時間時,服務器就能夠認爲客戶端已經中止了活動,纔會把session刪除以節省存儲空間。
  由此咱們能夠得出以下結論:
  關閉瀏覽器,只會是瀏覽器端內存裏的session cookie消失,但不會使保存在服務器端的session對象消失,一樣也不會使已經保存到硬盤上的持久化cookie消失。
二十7、打開兩個瀏覽器窗口訪問應用程序會使用同一個session仍是不一樣的session
  一般session cookie是不能跨窗口使用的,當你新開了一個瀏覽器窗口進入相同頁面時,系統會賦予你一個新的session id,這樣咱們信息共享的目的就達不到了。
  此時咱們能夠先把session id保存在persistent cookie中(經過設置session的最大有效時間),而後在新窗口中讀出來,就能夠獲得上一個窗口的session id了,這樣經過session cookie和persistent cookie的結合咱們就能夠實現了跨窗口的會話跟蹤。
二十8、如何使用會話顯示每一個客戶的訪問次數
  因爲客戶的訪問次數是一個整型的變量,但session的屬性類型中不能使用int,double,boolean等基本類型的變量,因此咱們要用到這些基本類型的封裝類型對象做爲session對象中屬性的值
  但像Integer是一種不可修改(Immutable)的數據結構:構建後就不能更改。這意味着每一個請求都必須建立新的Integer對象,以後使用setAttribute來代替以前存在的老的屬性的值。例如:
HttpSession session = request.getSession();
SomeImmutalbeClass value = (SomeImmutableClass)session.getAttribute(「SomeIdentifier」);
if (value= =null){
value = new SomeImmutableClass(…); // 新建立一個不可更改對象
}else{
value = new SomeImmutableClass(calculatedFrom(value)); // 對value從新計算後建立新的對象
}
session.setAttribute(「someIdentifier」,value); // 使用新建立的對象覆蓋原來的老的對象
二十9、如何使用會話累計用戶的數據
  使用可變的數據結構,好比數組、List、Map或含有可寫字段的應用程序專有的數據結構。經過這種方式,除非首次分配對象,不然不須要調用setAttribute。例如
HttpSession session = request.getSession();
SomeMutableClass value = (SomeMutableClass)session.getAttribute(「someIdentifier」);
if(value = = null){
value = new SomeMutableClass(…);
session.setAttribute(「someIdentifier」,value);
}else{
value.updateInternalAttribute(…); // 若是已經存在該對象則更新其屬性而不需從新設置屬性
}
三10、不可更改對象和可更改對象在會話數據更新時的不一樣處理
  不可更改對象由於一旦建立以後就不能更改,因此每次要修改會話中屬性的值的時候,都須要調用 setAttribute(「someIdentifier」,newValue)來代替原有的屬性的值,不然屬性的值不會被更新可更改對象由於其自身一 般提供了修改自身屬性的方法,因此每次要修改會話中屬性的值的時候,只要調用該可更改對象的相關修改自身屬性的方法就能夠了。這意味着咱們就不須要調用 setAttribute方法了。
 
 
 
-----------------------------------------
 
 

會話(Session)跟蹤是Web程序中經常使用的技術,用來跟蹤用戶的整個會話。經常使用的會話跟蹤技術是Cookie與Session。Cookie經過在客戶端記錄信息肯定用戶身份Session經過在服務器端記錄信息肯定用戶身份html

本章將系統地講述Cookie與Session機制,並比較說明何時不能用Cookie,何時不能用Session。java


1.1  Cookie機制git

在程序中,會話跟蹤是很重要的事情。理論上,一個用戶的全部請求操做都應該屬於同一個會話,而另外一個用戶的全部請求操做則應該屬於另外一個會話,兩者不能混淆。例如,用戶A在超市購買的任何商品都應該放在A的購物車內,不管是用戶A什麼時間購買的,這都是屬於同一個會話的,不能放入用戶B或用戶C的購物車內,這不屬於同一個會話。web

而Web應用程序是使用HTTP協議傳輸數據的。HTTP協議是無狀態的協議。一旦數據交換完畢,客戶端與服務器端的鏈接就會關閉,再次交換數據須要創建新的鏈接。這就意味着服務器沒法從鏈接上跟蹤會話。即用戶A購買了一件商品放入購物車內,當再次購買商品時服務器已經沒法判斷該購買行爲是屬於用戶A的會話仍是用戶B的會話了。要跟蹤該會話,必須引入一種機制。算法

Cookie就是這樣的一種機制。它能夠彌補HTTP協議無狀態的不足。在Session出現以前,基本上全部的網站都採用Cookie來跟蹤會話。數據庫

1.1.1  什麼是Cookie編程

Cookie意爲「甜餅」,是由W3C組織提出,最先由Netscape社區發展的一種機制。目前Cookie已經成爲標準,全部的主流瀏覽器如IE、Netscape、Firefox、Opera等都支持Cookie。跨域

因爲HTTP是一種無狀態的協議,服務器單從網絡鏈接上無從知道客戶身份。怎麼辦呢?就給客戶端們頒發一個通行證吧,每人一個,不管誰訪問都必須攜帶本身通行證。這樣服務器就能從通行證上確認客戶身份了。這就是Cookie的工做原理數組

Cookie其實是一小段的文本信息。客戶端請求服務器,若是服務器須要記錄該用戶狀態,就使用response向客 戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務 器。服務器檢查該Cookie,以此來辨認用戶狀態。服務器還能夠根據須要修改Cookie的內容。



查看某個網站頒發的Cookie很簡單。在瀏覽器地址欄輸入javascript:alert (document. cookie)就能夠了(須要有網才能查看)。JavaScript腳本會彈出一個對話框顯示本網站頒發的全部Cookie的內容,如圖1.1所示。


圖1.1  Baidu網站頒發的Cookie


圖1.1中彈出的對話框中顯示的爲Baidu網站的Cookie。其中第一行BAIDUID記錄的就是筆者的身份helloweenvsfei,只是Baidu使用特殊的方法將Cookie信息加密了。


注意:Cookie功能須要瀏覽器的支持。

若是瀏覽器不支持Cookie(如大部分手機中的瀏覽器)或者把Cookie禁用了,Cookie功能就會失效。

不一樣的瀏覽器採用不一樣的方式保存Cookie。

IE瀏覽器會在「C:\Documents and Settings\你的用戶名\Cookies」文件夾下以文本文件形式保存,一個文本文件保存一個Cookie。


1.1.2  記錄用戶訪問次數

Java中把Cookie封裝成了javax.servlet.http.Cookie類。每一個Cookie都是該Cookie類的對象。服務器經過操做Cookie類對象對客戶端Cookie進行操做。經過request.getCookie()獲取客戶端提交的全部Cookie(以Cookie[]數組形式返回),經過response.addCookie(Cookiecookie)向客戶端設置Cookie。

Cookie對象使用key-value屬性對的形式保存用戶狀態,一個Cookie對象保存一個屬性對,一個request或者response同時使用多個Cookie。由於Cookie類位於包javax.servlet.http.*下面,因此JSP中不須要import該類。


1.1.3  Cookie的不可跨域名性

不少網站都會使用Cookie。例如,Google會向客戶端頒發Cookie,Baidu也會向客戶端頒發Cookie。那瀏覽器訪問Google會不會也攜帶上Baidu頒發的Cookie呢?或者Google能不能修改Baidu頒發的Cookie呢?

答案是否認的。Cookie具備不可跨域名性。根據Cookie規範,瀏覽器訪問Google只會攜帶Google的Cookie,而不會攜帶Baidu的Cookie。Google也只能操做Google的Cookie,而不能操做Baidu的Cookie。

Cookie在客戶端是由瀏覽器來管理的。瀏覽器可以保證Google只會操做Google的Cookie而不會操做 Baidu的Cookie,從而保證用戶的隱私安全。瀏覽器判斷一個網站是否能操做另外一個網站Cookie的依據是域名。Google與Baidu的域名 不同,所以Google不能操做Baidu的Cookie。

須要注意的是,雖然網站images.google.com與網站www.google.com同屬於Google,可是域名不同,兩者一樣不能互相操做彼此的Cookie。


注意:用戶登陸網站www.google.com以後會發現訪問images.google.com時登陸信息仍然有效,而普通的Cookie是作不到的。這是由於Google作了特殊處理。本章後面也會對Cookie作相似的處理。


1.1.4  Unicode編碼:保存中文

中文與英文字符不一樣,中文屬於Unicode字符,在內存中佔4個字符,而英文屬於ASCII字符,內存中只佔2個字節。Cookie中使用Unicode字符時須要對Unicode字符進行編碼,不然會亂碼。


提示:Cookie中保存中文只能編碼。通常使用UTF-8編碼便可。不推薦使用GBK等中文編碼,由於瀏覽器不必定支持,並且JavaScript也不支持GBK編碼。


1.1.5  BASE64編碼:保存二進制圖片

Cookie不只可使用ASCII字符與Unicode字符,還可使用二進制數據。例如在Cookie中使用數字證書,提供安全度。使用二進制數據時也須要進行編碼。

%注意:本程序僅用於展現Cookie中能夠存儲二進制內容,並不實用。因爲瀏覽器每次請求服務器都會攜帶Cookie,所以Cookie內容不宜過多,不然影響速度。Cookie的內容應該少而精。


1.1.6  設置Cookie的全部屬性

除了name與value以外,Cookie還具備其餘幾個經常使用的屬性。每一個屬性對應一個getter方法與一個setter方法。Cookie類的全部屬性如表1.1所示。

表1.1  Cookie經常使用屬性

屬  性  名

描    述

String name

該Cookie的名稱。Cookie一旦建立,名稱便不可更改

Object value

該Cookie的值。若是值爲Unicode字符,須要爲字符編碼。若是值爲二進制數據,則須要使用BASE64編碼

int maxAge

該Cookie失效的時間,單位秒。若是爲正數,則該Cookie在maxAge秒以後失效。若是爲負數,該Cookie爲臨時Cookie,關閉瀏覽器即失效,瀏覽器也不會以任何形式保存該Cookie。若是爲0,表示刪除該Cookie。默認爲–1

boolean secure

該Cookie是否僅被使用安全協議傳輸。安全協議。安全協議有HTTPS,SSL等,在網絡上傳輸數據以前先將數據加密。默認爲false

String path

該Cookie的使用路徑。若是設置爲「/sessionWeb/」,則只有contextPath爲「/sessionWeb」的程序能夠訪問該Cookie。若是設置爲「/」,則本域名下contextPath均可以訪問該Cookie。注意最後一個字符必須爲「/」

String domain

能夠訪問該Cookie的域名。若是設置爲「.google.com」,則全部以「google.com」結尾的域名均可以訪問該Cookie。注意第一個字符必須爲「.」

String comment

該Cookie的用處說明。瀏覽器顯示Cookie信息的時候顯示該說明

int version

該Cookie使用的版本號。0表示遵循Netscape的Cookie規範,1表示遵循W3C的RFC 2109規範


1.1.7  Cookie的有效期

Cookie的maxAge決定着Cookie的有效期,單位爲秒(Second)。Cookie中經過getMaxAge()方法與setMaxAge(int maxAge)方法來讀寫maxAge屬性。

若是maxAge屬性爲正數,則表示該Cookie會在maxAge秒以後自動失效。瀏覽器會將maxAge爲正數的 Cookie持久化,即寫到對應的Cookie文件中。不管客戶關閉了瀏覽器仍是電腦,只要還在maxAge秒以前,登陸網站時該Cookie仍然有效。 下面代碼中的Cookie信息將永遠有效。


Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie

cookie.setMaxAge(Integer.MAX_VALUE);           // 設置生命週期爲MAX_VALUE

response.addCookie(cookie);                    // 輸出到客戶端


若是maxAge爲負數,則表示該Cookie僅在本瀏覽器窗口以及本窗口打開的子窗口內有效,關閉窗口後該 Cookie即失效。maxAge爲負數的Cookie,爲臨時性Cookie,不會被持久化,不會被寫到Cookie文件中。Cookie信息保存在瀏 覽器內存中,所以關閉瀏覽器該Cookie就消失了。Cookie默認的maxAge值爲–1。

若是maxAge爲0,則表示刪除該Cookie。Cookie機制沒有提供刪除Cookie的方法,所以經過設置該Cookie即時失效實現刪除Cookie的效果。失效的Cookie會被瀏覽器從Cookie文件或者內存中刪除,


例如:

Cookie cookie = new Cookie("username","helloweenvsfei");   // 新建Cookie

cookie.setMaxAge(0);                          // 設置生命週期爲0,不能爲負數

response.addCookie(cookie);                    // 必須執行這一句


response對象提供的Cookie操做方法只有一個添加操做add(Cookie cookie)。

要想修改Cookie只能使用一個同名的Cookie來覆蓋原來的Cookie,達到修改的目的。刪除時只須要把maxAge修改成0便可。


注意:從客戶端讀取Cookie時,包括maxAge在內的其餘屬性都是不可讀的,也不會被提交。瀏覽器提交Cookie時只會提交name與value屬性。maxAge屬性只被瀏覽器用來判斷Cookie是否過時。


1.1.8  Cookie的修改、刪除

Cookie並不提供修改、刪除操做。若是要修改某個Cookie,只須要新建一個同名的Cookie,添加到response中覆蓋原來的Cookie。

若是要刪除某個Cookie,只須要新建一個同名的Cookie,並將maxAge設置爲0,並添加到response中覆蓋原來的Cookie。注意是0而不是負數。負數表明其餘的意義。讀者能夠經過上例的程序進行驗證,設置不一樣的屬性。


注意:修改、刪除Cookie時,新建的Cookie除value、maxAge以外的全部屬性,例如name、path、domain等,都要與原Cookie徹底同樣。不然,瀏覽器將視爲兩個不一樣的Cookie不予覆蓋,致使修改、刪除失敗。


1.1.9  Cookie的域名

Cookie是不可跨域名的。域名www.google.com頒發的Cookie不會被提交到域名www.baidu.com去。這是由Cookie的隱私安全機制決定的。隱私安全機制可以禁止網站非法獲取其餘網站的Cookie。

正常狀況下,同一個一級域名下的兩個二級域名如www.helloweenvsfei.com和 images.helloweenvsfei.com也不能交互使用Cookie,由於兩者的域名並不嚴格相同。若是想全部 helloweenvsfei.com名下的二級域名均可以使用該Cookie,須要設置Cookie的domain參數,例如:

Cookie cookie = new Cookie("time","20080808"); // 新建Cookie

cookie.setDomain(".helloweenvsfei.com");           // 設置域名

cookie.setPath("/");                              // 設置路徑

cookie.setMaxAge(Integer.MAX_VALUE);               // 設置有效期

response.addCookie(cookie);                       // 輸出到客戶端


讀者能夠修改本機C:\WINDOWS\system32\drivers\etc下的hosts文件來配置多個臨時域名,而後使用setCookie.jsp程序來設置跨域名Cookie驗證domain屬性。

注意:domain參數必須以點(".")開始。另外,name相同但domain不一樣的兩個Cookie是兩個不一樣的Cookie。若是想要兩個域名徹底不一樣的網站共有Cookie,能夠生成兩個Cookie,domain屬性分別爲兩個域名,輸出到客戶端。


1.1.10  Cookie的路徑

domain屬性決定運行訪問Cookie的域名,而path屬性決定容許訪問Cookie的路徑(ContextPath)。例如,若是隻容許/sessionWeb/下的程序使用Cookie,能夠這麼寫:

Cookie cookie = new Cookie("time","20080808");     // 新建Cookie

cookie.setPath("/session/");                          // 設置路徑

response.addCookie(cookie);                           // 輸出到客戶端

設置爲「/」時容許全部路徑使用Cookie。path屬性須要使用符號「/」結尾。name相同但domain相同的兩個Cookie也是兩個不一樣的Cookie。


注意:頁面只能獲取它屬於的Path的Cookie。例如/session/test/a.jsp不能獲取到路徑爲/session/abc/的Cookie。使用時必定要注意。


1.1.11  Cookie的安全屬性

HTTP協議不只是無狀態的,並且是不安全的。使用HTTP協議的數據不通過任何加密就直接在網絡上傳播,有被截獲的可 能。使用HTTP協議傳輸很機密的內容是一種隱患。若是不但願Cookie在HTTP等非安全協議中傳輸,能夠設置Cookie的secure屬性爲 true。瀏覽器只會在HTTPS和SSL等安全協議中傳輸此類Cookie。下面的代碼設置secure屬性爲true:


Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie

cookie.setSecure(true);                           // 設置安全屬性

response.addCookie(cookie);                        // 輸出到客戶端


提示:secure屬性並不能對Cookie內容加密,於是不能保證絕對的安全性。若是須要高安全性,須要在程序中對Cookie內容加密、解密,以防泄密。


1.1.12  JavaScript操做Cookie

Cookie是保存在瀏覽器端的,所以瀏覽器具備操做Cookie的先決條件。瀏覽器可使用腳本程序如 JavaScript或者VBScript等操做Cookie。這裏以JavaScript爲例介紹經常使用的Cookie操做。例以下面的代碼會輸出本頁面 全部的Cookie。

<script>document.write(document.cookie);</script>

因爲JavaScript可以任意地讀寫Cookie,有些好事者便想使用JavaScript程序去窺探用戶在其餘網 站的Cookie。不過這是徒勞的,W3C組織早就意識到JavaScript對Cookie的讀寫所帶來的安全隱患並加以防備了,W3C標準的瀏覽器會 阻止JavaScript讀寫任何不屬於本身網站的Cookie。換句話說,A網站的JavaScript程序讀寫B網站的Cookie不會有任何結果。


1.1.13  案例:永久登陸

若是用戶是在本身家的電腦上上網,登陸時就能夠記住他的登陸信息,下次訪問時不須要再次登陸,直接訪問便可。實現方法是把登陸信息如帳號、密碼等保存在Cookie中,並控制Cookie的有效期,下次訪問時再驗證Cookie中的登陸信息便可。

保存登陸信息有多種方案。最直接的是把用戶名與密碼都保持到Cookie中,下次訪問時檢查Cookie中的用戶名與密碼,與數據庫比較。這是一種比較危險的選擇,通常不把密碼等重要信息保存到Cookie中

還有一種方案是把密碼加密後保存到Cookie中,下次訪問時解密並與數據庫比較。這種方案略微安全一些。若是不但願保存密碼,還能夠把登陸的時間戳保存到Cookie與數據庫中,到時只驗證用戶名與登陸時間戳就能夠了。

這幾種方案驗證帳號時都要查詢數據庫。

本例將採用另外一種方案,只在登陸時查詢一次數據庫,之後訪問驗證登陸信息時再也不查詢數據庫。實現方式是把帳號按照必定的規則加密後,連同帳號一塊保存到Cookie中。下次訪問時只須要判斷帳號的加密規則是否正確便可。本例把帳號保存到名爲account的Cookie中,把帳號連同密鑰用MD1算法加密後保存到名爲ssid的Cookie中。驗證時驗證Cookie中的帳號與密鑰加密後是否與Cookie中的ssid相等。相關代碼以下:

代碼1.8 loginCookie.jsp

<%@ page language="java"pageEncoding="UTF-8" isErrorPage="false" %>

<%!                                                  // JSP方法

    private static final String KEY =":cookie@helloweenvsfei.com";
                                                     // 密鑰 

    public final static String calcMD1(Stringss) { // MD1 加密算法

       String s = ss==null ?"" : ss;                  // 若爲null返回空

       char hexDigits[] = { '0','1', '2', '3', '4', '1', '6', '7', '8', '9',
       'a', 'b', 'c', 'd', 'e', 'f' };                        // 字典

       try {

        byte[] strTemp =s.getBytes();                          // 獲取字節

        MessageDigestmdTemp = MessageDigest.getInstance("MD1"); // 獲取MD1

       mdTemp.update(strTemp);                                // 更新數據

        byte[] md =mdTemp.digest();                        // 加密

        int j =md.length;                                 // 加密後的長度

        char str[] = newchar[j * 2];                       // 新字符串數組

        int k =0;                                         // 計數器k

        for (int i = 0; i< j; i++) {                       // 循環輸出

         byte byte0 =md[i];

         str[k++] =hexDigits[byte0 >>> 4 & 0xf];

         str[k++] =hexDigits[byte0 & 0xf];

        }

        return newString(str);                             // 加密後字符串

       } catch (Exception e){return null; }

    }

%>

<%

   request.setCharacterEncoding("UTF-8");             // 設置request編碼

    response.setCharacterEncoding("UTF-8");        // 設置response編碼

   

    String action =request.getParameter("action"); // 獲取action參數

   

    if("login".equals(action)){                       // 若是爲login動做

        String account =request.getParameter("account");
                                                     // 獲取account參數

        String password =request.getParameter("password");
                                                     // 獲取password參數

        int timeout = newInteger(request.getParameter("timeout"));
                                                     // 獲取timeout參數

              

        String ssid =calcMD1(account + KEY); // 把帳號、密鑰使用MD1加密後保存

       

        CookieaccountCookie = new Cookie("account", account);
                                                     // 新建Cookie

       accountCookie.setMaxAge(timeout);              // 設置有效期

       

        Cookie ssidCookie =new Cookie("ssid", ssid);   // 新建Cookie

       ssidCookie.setMaxAge(timeout);                 // 設置有效期

       

       response.addCookie(accountCookie);             // 輸出到客戶端

       response.addCookie(ssidCookie);            // 輸出到客戶端

       

        // 從新請求本頁面,參數中帶有時間戳,禁止瀏覽器緩存頁面內容

       response.sendRedirect(request.getRequestURI() + "?" + System.
        currentTimeMillis());

        return;

    }

    elseif("logout".equals(action)){                  // 若是爲logout動做

       

        CookieaccountCookie = new Cookie("account", "");
                                                 // 新建Cookie,內容爲空

       accountCookie.setMaxAge(0);                // 設置有效期爲0,刪除

              

        Cookie ssidCookie =new Cookie("ssid", ""); // 新建Cookie,內容爲空

       ssidCookie.setMaxAge(0);                   // 設置有效期爲0,刪除

       response.addCookie(accountCookie);         // 輸出到客戶端

       response.addCookie(ssidCookie);         // 輸出到客戶端

        //從新請求本頁面,參數中帶有時間戳,禁止瀏覽器緩存頁面內容

       response.sendRedirect(request.getRequestURI() + "?" + System.
        currentTimeMillis());

        return;

    }

    boolean login = false;                        // 是否登陸

    String account = null;                        // 帳號

    String ssid = null;                           // SSID標識

   

    if(request.getCookies() !=null){               // 若是Cookie不爲空

        for(Cookie cookie :request.getCookies()){  // 遍歷Cookie

           if(cookie.getName().equals("account"))  // 若是Cookie名爲
                                                    account

               account = cookie.getValue();       // 保存account內容

           if(cookie.getName().equals("ssid")) // 若是爲SSID

               ssid = cookie.getValue();          // 保存SSID內容

        }

    }

    if(account != null && ssid !=null){    // 若是account、SSID都不爲空

        login =ssid.equals(calcMD1(account + KEY));
                                      // 若是加密規則正確, 則視爲已經登陸

    }

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">

       <legend><%= login ? "歡迎您回來" : "請先登陸"%></legend>

        <% if(login){%>

            歡迎您, ${ cookie.account.value }. &nbsp;&nbsp;

           <a href="${ pageContext.request.requestURI }?action=logout">
            註銷</a>

        <% } else {%>

        <formaction="${ pageContext.request.requestURI }?action=login"
        method="post">

           <table>

               <tr><td>帳號: </td>

                   <td><input type="text"name="account" style="width:
                   200px; "></td>

               </tr>

               <tr><td>密碼: </td>

                   <td><inputtype="password" name="password"></td>

               </tr>

               <tr>

                   <td>有效期: </td>

                   <td><inputtype="radio" name="timeout" value="-1"
                   checked> 關閉瀏覽器即失效 <br/> <input type="radio"
                   name="timeout" value="<%= 30 *24 * 60 * 60 %>"> 30天
                   內有效 <br/><input type="radio" name="timeout" value=
                   "<%= Integer.MAX_VALUE %>"> 永久有效 <br/> </td> </tr>

               <tr><td></td>

                   <td><input type="submit"value=" 登  錄 " class=
                   "button"></td>

               </tr>

           </table>

        </form>

        <% } %>

登陸時能夠選擇登陸信息的有效期:關閉瀏覽器即失效、30天內有效與永久有效。經過設置Cookie的age屬性來實現,注意觀察代碼。運行效果如圖1.7所示。


圖1.7  永久登陸

提示:該加密機制中最重要的部分爲算法與密鑰。因爲MD1算法的不可逆性,即便用戶知道了帳號與加密後的字符串,也不可能解密獲得密鑰。所以,只要保管好密鑰與算法,該機制就是安全的。


1.2  Session機制

除了使用Cookie,Web應用程序中還常用Session來記錄客戶端狀態。Session是服務器端使用的一種記錄客戶端狀態的機制,使用上比Cookie簡單一些,相應的也增長了服務器的存儲壓力

1.2.1  什麼是Session

Session是另外一種記錄客戶狀態的機制,不一樣的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只須要從該Session中查找該客戶的狀態就能夠了。

若是說Cookie機制是經過檢查客戶身上的「通行證」來肯定客戶身份的話,那麼Session機制就是經過檢查服務器上的「客戶明細表」來確認客戶身份。Session至關於程序在服務器上創建的一份客戶檔案,客戶來訪的時候只須要查詢客戶檔案表就能夠了。

1.2.2  實現用戶登陸

Session對應的類爲javax.servlet.http.HttpSession類。每一個來訪者對應一個Session對象,全部該客戶的狀態信息都保存在這個Session對象裏。Session對象是在客戶端第一次請求服務器的時候建立的。 Session也是一種key-value的屬性對,經過getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法讀寫客戶狀態信息。Servlet裏經過request.getSession()方法獲取該客戶的 Session,

例如:

HttpSession session = request.getSession();       // 獲取Session對象

session.setAttribute("loginTime", new Date());     // 設置Session中的屬性

   

out.println("登陸時間爲:" +(Date)session.getAttribute("loginTime"));      // 獲取Session屬性

request還可使用getSession(boolean create)來獲取Session。區別是若是該客戶的Session不存在,request.getSession()方法會返回null,而 getSession(true)會先建立Session再將Session返回。

Servlet中必須使用request來編程式獲取HttpSession對象,而JSP中內置了Session隱藏 對象,能夠直接使用。若是使用聲明瞭<%@page session="false" %>,則Session隱藏對象不可用。下面的例子使用Session記錄客戶帳號信息。

源代碼以下:

代碼1.9  session.jsp

<%@ page language="java" pageEncoding="UTF-8"%>

<jsp:directive.page import="com.helloweenvsfei.sessionWeb.bean.Person"/>

<jsp:directive.page import="java.text.SimpleDateFormat"/>

<jsp:directive.page import="java.text.DateFormat"/>

<jsp:directive.page import="java.util.Date"/>

<%!

    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");         // 日期格式化器

%>

<%

    response.setCharacterEncoding("UTF-8");        // 設置request編碼

    Person[] persons =

    {          

       // 基礎數據,保存三我的的信息

        new Person("Liu Jinghua","password1", 34, dateFormat.parse
        ("1982-01-01")),

        new Person("Hello Kitty","hellokitty", 23, dateFormat.parse
        ("1984-02-21")),

        new Person("Garfield", "garfield_pass",23, dateFormat.parse
        ("1994-09-12")),

     };

   

    String message = "";                      // 要顯示的消息

   

    if(request.getMethod().equals("POST"))

    {

        // 若是是POST登陸       

        for(Person person :persons)

        {          

            // 遍歷基礎數據,驗證帳號、密碼

            // 若是用戶名正確且密碼正確

           if(person.getName().equalsIgnoreCase(request.getParameter("username"))&&person.getPassword().equals(request.getParameter("password")))

           {              

               // 登陸成功,設置將用戶的信息以及登陸時間保存到Session

               session.setAttribute("person", person);                   // 保存登陸的Person

               session.setAttribute("loginTime", new Date());          // 保存登陸的時間              

               response.sendRedirect(request.getContextPath() + "/welcome.jsp");

               return;

            }

        }      

        message = "用戶名密碼不匹配,登陸失敗。";       // 登陸失敗

    }

%>

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01Transitional//EN">

<html>

    // ... HTML代碼爲一個FORM表單,代碼略,請看隨書光盤

</html>


登陸界面驗證用戶登陸信息,若是登陸正確,就把用戶信息以及登陸時間保存進Session,而後轉到歡迎頁面welcome.jsp。welcome.jsp中從Session中獲取信息,並將用戶資料顯示出來。

welcome.jsp代碼以下:

代碼1.10  welcome.jsp

<%@ page language="java" pageEncoding="UTF-8"%>

<jsp:directive.pageimport="com.helloweenvsfei.sessionWeb.bean.Person"/>

<jsp:directive.page import="java.text.SimpleDateFormat"/>

<jsp:directive.page import="java.text.DateFormat"/>

<jsp:directive.page import="java.util.Date"/>

<%!

    DateFormat dateFormat = newSimpleDateFormat("yyyy-MM-dd");         // 日期格式化器

%>

<%

    Person person =(Person)session.getAttribute("person");                       // 獲取登陸的person

    Date loginTime =(Date)session.getAttribute("loginTime");                     // 獲取登陸時間

%>

    // ... 部分HTML代碼略

            <table>

               <tr><td>您的姓名:</td>

                   <td><%= person.getName()%></td>

               </tr>

               <tr><td>登陸時間:</td>

                   <td><%= loginTime%></td>

               </tr>

               <tr><td>您的年齡:</td>

                   <td><%= person.getAge()%></td>

               </tr>

               <tr><td>您的生日:</td>

                   <td><%=dateFormat.format(person.getBirthday()) %></td>

               </tr>

            </table>

程序運行效果如圖1.8所示。


圖1.8  使用Session記錄用戶信息

注意程序中Session中直接保存了Person類對象與Date類對象,使用起來要比Cookie方便。

當多個客戶端執行程序時,服務器會保存多個客戶端的Session。獲取Session的時候也不須要聲明獲取誰的Session。Session機制決定了當前客戶只會獲取到本身的Session,而不會獲取到別人的Session。各客戶的Session也彼此獨立,互不可見


提示Session的使用比Cookie方便,可是過多的Session存儲在服務器內存中,會對服務器形成壓力。


1.2.3  Session的生命週期

Session保存在服務器端。爲了得到更高的存取速度,服務器通常把Session放在內存裏。每一個用戶都會有一個獨立的Session。若是Session內容過於複雜,當大量客戶訪問服務器時可能會致使內存溢出。所以,Session裏的信息應該儘可能精簡。

Session在用戶第一次訪問服務器的時候自動建立。須要注意只有訪問JSP、Servlet等程序時纔會建立Session,只訪問HTML、IMAGE等靜態資源並不會建立Session。若是還沒有生成Session,也可使用request.getSession(true)強制生成Session。

Session生成後,只要用戶繼續訪問,服務器就會更新Session的最後訪問時間,並維護該Session。用戶每訪問服務器一次,不管是否讀寫Session,服務器都認爲該用戶的Session「活躍(active)」了一次。


1.2.4  Session的有效期

因爲會有愈來愈多的用戶訪問服務器,所以Session也會愈來愈多。爲防止內存溢出,服務器會把長時間內沒有活躍的Session從內存刪除。這個時間就是Session的超時時間。若是超過了超時時間沒訪問過服務器,Session就自動失效了。

Session的超時時間爲maxInactiveInterval屬性,能夠經過對應的getMaxInactiveInterval()獲取,經過setMaxInactiveInterval(longinterval)修改。

Session的超時時間也能夠在web.xml中修改。另外,經過調用Session的invalidate()方法可使Session失效。


1.2.5  Session的經常使用方法

Session中包括各類方法,使用起來要比Cookie方便得多。Session的經常使用方法如表1.2所示。

表1.2  HttpSession的經常使用方法

方  法  名

描    述

void setAttribute(String attribute, Object value)

設置Session屬性。value參數能夠爲任何Java Object。一般爲Java Bean。value信息不宜過大

String getAttribute(String attribute)

返回Session屬性

Enumeration getAttributeNames()

返回Session中存在的屬性名

void removeAttribute(String attribute)

移除Session屬性

String getId()

返回Session的ID。該ID由服務器自動建立,不會重複

long getCreationTime()

返回Session的建立日期。返回類型爲long,常被轉化爲Date類型,例如:Date createTime = new Date(session.get CreationTime())

long getLastAccessedTime()

返回Session的最後活躍時間。返回類型爲long

int getMaxInactiveInterval()

返回Session的超時時間。單位爲秒。超過該時間沒有訪問,服務器認爲該Session失效

void setMaxInactiveInterval(int second)

設置Session的超時時間。單位爲秒

void putValue(String attribute, Object value)

不推薦的方法。已經被setAttribute(String attribute, Object Value)替代

Object getValue(String attribute)

不被推薦的方法。已經被getAttribute(String attr)替代

boolean isNew()

返回該Session是不是新建立的

void invalidate()

使該Session失效

Tomcat中Session的默認超時時間爲20分鐘。經過setMaxInactiveInterval(int seconds)修改超時時間。能夠修改web.xml改變Session的默認超時時間。例如修改成60分鐘:

<session-config>

   <session-timeout>60</session-timeout>      <!-- 單位:分鐘 -->

</session-config>


注意:<session-timeout>參數的單位爲分鐘,而setMaxInactiveInterval(int s)單位爲秒。


1.2.6  Session對瀏覽器的要求

雖然Session保存在服務器,對客戶端是透明的,它的正常運行仍然須要客戶端瀏覽器的支持。這是由於Session 須要使用Cookie做爲識別標誌。HTTP協議是無狀態的,Session不能依據HTTP鏈接來判斷是否爲同一客戶,所以服務器向客戶端瀏覽器發送一 個名爲JSESSIONID的Cookie,它的值爲該Session的id(也就是HttpSession.getId()的返回值)。Session 依據該Cookie來識別是否爲同一用戶。

該Cookie爲服務器自動生成的,它的maxAge屬性通常爲–1,表示僅當前瀏覽器內有效,而且各瀏覽器窗口間不共享,關閉瀏覽器就會失效。

所以同一機器的兩個瀏覽器窗口訪問服務器時,會生成兩個不一樣的Session。可是由瀏覽器窗口內的連接、腳本等打開的新窗口(也就是說不是雙擊桌面瀏覽器圖標等打開的窗口)除外。這類子窗口會共享父窗口的Cookie,所以會共享一個Session。


注意:新開的瀏覽器窗口會生成新的Session,但子窗口除外。子窗口會共用父窗口的Session。例如,在連接上右擊,在彈出的快捷菜單中選擇「在新窗口中打開」時,子窗口即可以訪問父窗口的Session。

若是客戶端瀏覽器將Cookie功能禁用,或者不支持Cookie怎麼辦?例如,絕大多數的手機瀏覽器都不支持Cookie。Java Web提供了另外一種解決方案:URL地址重寫。


1.2.7  URL地址重寫

URL地址重寫是對客戶端不支持Cookie的解決方案。URL地址重寫的原理是將該用戶Session的id信息重寫 到URL地址中。服務器可以解析重寫後的URL獲取Session的id。這樣即便客戶端不支持Cookie,也可使用Session來記錄用戶狀態。 HttpServletResponse類提供了encodeURL(Stringurl)實現URL地址重寫,例如:

<td>

    <a href="<%=response.encodeURL("index.jsp?c=1&wd=Java") %>">
    Homepage</a>

</td>

該方法會自動判斷客戶端是否支持Cookie。若是客戶端支持Cookie,會將URL原封不動地輸出來。若是客戶端不支持Cookie,則會將用戶Session的id重寫到URL中。重寫後的輸出多是這樣的:

<td>

    <ahref="index.jsp;jsessionid=0CCD096E7F8D97B0BE608AFDC3E1931E?c=
    1&wd=Java">Homepage</a>

</td>

即在文件名的後面,在URL參數的前面添加了字符串「;jsessionid=XXX」。其中XXX爲Session的 id。分析一下能夠知道,增添的jsessionid字符串既不會影響請求的文件名,也不會影響提交的地址欄參數。用戶單擊這個連接的時候會把 Session的id經過URL提交到服務器上,服務器經過解析URL地址得到Session的id。

若是是頁面重定向(Redirection),URL地址重寫能夠這樣寫:

<%

    if(「administrator」.equals(userName))

    {

       response.sendRedirect(response.encodeRedirectURL(「administrator.jsp」));

        return;

    }

%>

效果跟response.encodeURL(String url)是同樣的:若是客戶端支持Cookie,生成原URL地址,若是不支持Cookie,傳回重寫後的帶有jsessionid字符串的地址。

對於WAP程序,因爲大部分的手機瀏覽器都不支持Cookie,WAP程序都會採用URL地址重寫來跟蹤用戶會話。好比用友集團的移動商街等。


注意:TOMCAT判斷客戶端瀏覽器是否支持Cookie的依據是請求中是否含有Cookie。儘管客戶端可能會支持Cookie,可是因爲第一次請求時不會攜帶任何Cookie(由於並沒有任何Cookie能夠攜帶),URL地址重寫後的地址中仍然會帶有jsessionid。當第二次訪問時服務器已經在瀏覽器中寫入Cookie了,所以URL地址重寫後的地址中就不會帶有jsessionid了。


1.2.8  Session中禁止使用Cookie

既然WAP上大部分的客戶瀏覽器都不支持Cookie,索性禁止Session使用Cookie,統一使用URL地址重寫會更好一些。Java Web規範支持經過配置的方式禁用Cookie。下面舉例說一下怎樣經過配置禁止使用Cookie。

打開項目sessionWeb的WebRoot目錄下的META-INF文件夾(跟WEB-INF文件夾同級,若是沒有則建立),打開context.xml(若是沒有則建立),編輯內容以下:

代碼1.11 /META-INF/context.xml

<?xml version='1.0' encoding='UTF-8'?>

<Context path="/sessionWeb"cookies="false">

</Context>


或者修改Tomcat全局的conf/context.xml,修改內容以下:

代碼1.12  context.xml

<!-- The contents of this file will be loaded for eachweb application -->

<Context cookies="false">

    <!-- ... 中間代碼略 -->

</Context>

部署後TOMCAT便不會自動生成名JSESSIONID的Cookie,Session也不會以Cookie爲識別標誌,而僅僅以重寫後的URL地址爲識別標誌了。


注意:該配置只是禁止Session使用Cookie做爲識別標誌,並不能阻止其餘的Cookie讀寫。也就是說服務器不會自動維護名爲JSESSIONID的Cookie了,可是程序中仍然能夠讀寫其餘的Cookie。

相關文章
相關標籤/搜索