首頁  >  文章  >  web前端  >  Cookie/Session機制介紹

Cookie/Session機制介紹

一个新手
一个新手原創
2017-09-23 09:09:551564瀏覽

會話(Session)追蹤是Web程式中常用的技術,用來追蹤使用者的整個會話。常用的會話追蹤技術是Cookie與Session。 Cookie透過在客戶端記錄資訊來確定使用者身分Session透過在伺服器端記錄資訊來確定使用者身分

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


1.1  Cookie機制

在程式中,會話追蹤是很重要的事情。理論上,一個使用者的所有請求操作都應該屬於同一個會話,而另一個使用者的所有請求操作則應該屬於另一個會話,而二者不能混淆。例如,用戶A在超市購買的任何商品都應該放在A的購物車內,不論是用戶A什麼時間購買的,這都是屬於同一個會話的,不能放入用戶B或用戶C的購物車內,這不屬於同一個會話。

而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常用屬性

屬  性  名稱

Tor   述

#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,且無法為負數#11205;          // 必須執行這句話

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/");                          //設定路徑

     // 輸出到客戶端

設定為「/」時允許所有路徑使用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);                           // 設定安全屬性上(        // 輸出至客戶端 #


提示: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, '1', '2, '33' ', '6', '7', '8', '9',

       'a', 'b', 'c', 'd', 'e', 'f' };             
##       try {

        byte[] strTemp =s.getBytes();            MessageDigestmdTemp = MessageDigest.getInstance("MD1"); // 取得MD1

       mdTemp.update(strTemp);                         );                        // 加密上

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

        char str[] = newchar[j 

*

 2];                                                      // 計數器k

        for (int i = 0; i< j; i++) {                      str[k++] =hexDigits[byte0 > ;>> 4 & 0xf];

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

                         // 加密後字串

       } catch (Exception e){return null; }

    }

##%>

#    }

##%>

<%

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

#    response.set? # #    String action =request.getParameter("action"); // 取得action參數

   

    if("login".equals(action)){     

#        String account =request.getParameter("account");

                          // 取得account參數

        String password =request.getParameter("password");

                          // 取得password參數

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

              ,

##       String ssid =calc

        String ssid =calc

.把帳號、金鑰使用MD1加密後保存

       

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

#       accountCookie.setMaxAge (timeout);              // 設定有效期限

       

#        C idCookie.setMaxAge(timeout); // 設定有效期限

       

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

       

        // 重新請求本頁面,參數中帶有時間戳,禁止瀏覽器快取頁面內容

       res +vsendRedirect(request. System.

        currentTimeMillis());

        return;

    }

    // 如果為logout動作

       

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

       accountCookie.setMaxAge(0);       為0,刪除

              

        Cookie ssidCookie =新 C ;                   //設定有效期限為0,刪除

       response.addCookie(accountCookie); Cookie(ssidCookie);         // 輸出至客戶端

        //重新請求此頁面,參數中帶有時間戳,禁止瀏覽器快取頁面內容

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

        return;

#    }

    boolean login = false;       account = null;                        // 帳號

    String ssid = null;                           // SSID 識別        // 若Cookie不為空

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

           if(cookie.getName().equals("account"))  // 若Cookie名稱為
                         account

#               account = cookie.getValue();    # 

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

                   }

    }

    if(account != null && ssid !=null){    // 如果account、SSID都不為空

 + KEY));

                                  或無法登錄HTML PUBLIC "- //W3C//DTD HTML 4.01Transitional//EN">

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

        <% if(login){%>

            歡迎您, ${ cookie.account.value } "${ pageContext.request.requestURI }?action=logout">

            註銷

      "${ pageContext.request.requestURI }?action=login"

        method="post">

           

              

##                         200px ; "> ;


              

               

              

            

                  


              


  # "按鈕"<               #        

        <% } %>

#登入時可選擇登入資訊的有效期限:關閉瀏覽器即失效、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"%>

<%!

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

%>

<%

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

    Person[

#       // 基礎數據,保存三個人的信息


        new Person("Liu Jinghua","password1", 34, dateFormat.parse

   "#   ,

        new Person("Hello Kitty","hellokitty", 23, dateFormat.parse

        ("1984-02-21")),
")),

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

##    String message = "";                      // 請顯示中的訊息

##"#)

        // 若使用POST登入       

        for(Person person : #            // 遍歷基礎數據,並驗證帳號、密碼

            // 若使用者名稱正確且正確密碼

           if(person.getName().equalsIgnoreCase(request.Parameter)(person.getName().equalsIgnoreCase(request.a). 。 ##               session.setAttribute( "person", person);                   // 儲存登錄中的Person

          );  // 儲存登入的時間              

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

               return;


##。

            }

        }      

      #%> ;

    // .. . HTML程式碼為一個FORM表單,程式碼略,請看隨書光碟

登入介面驗證使用者登入訊息,如果登入正確,就把使用者資訊以及登入時間儲存進Session,然後前往歡迎頁面welcome.jsp。 welcome.jsp中從Session中獲取信息,並將用戶資料顯示出來。

welcome.jsp程式碼如下:

程式碼1.10  welcome.jsp

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

<%!

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

##%>%>

%>

%>

%>

%>

%>

%>

%>

%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%>###%> ###<%######    Person person =(Person)session.getAttribute("person");                 

    Date loginTime =(Date)session.getAttribute("loginTime");                   

           
帳號:
;
;有效:           關閉瀏覽器即失效
>                    name="timeout" value="*

24 ##*> > 30天

                   內效
>

               <  

              

                       

              

   

                  

                  

<%= person.getName()% >
<%= loginTime%>
<%= person.getAge()%>您的生日: <%=dateFormat.format(oxy  

           

程式運作效果如圖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的常用方法

##String getId()傳回Session的ID。 ID由伺服器自動創建,不會重複long getCreationTime()傳回Session的建立日期。傳回類型為long,常轉換為Date類型,例如:Date createTime = new Date(session.get CreationTime())long getLastAccessedTime()返回Session的最後活躍時間。傳回型別為longint 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分鐘:

   60     

##


注意:參數的單位為分鐘,而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位址重寫,例如:

此方法會自動判斷客戶端是否支援Cookie。如果客戶端支援Cookie,會將URL原封不動地輸出來。如果客戶端不支援Cookie,則會將使用者Session的id重寫到URL中。重寫後的輸出可能是這樣的:

即在檔案名稱的後面,在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”));

  >

效果跟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,統一使用網址重寫會比較好一些。 Java Web規格支援透過設定的方式停用Cookie。下面舉例說一下怎樣透過設定禁止使用Cookie。

開啟專案sessionWeb的WebRoot目錄下的META-INF資料夾(跟WEB-INF資料夾同級,如果沒有則建立),開啟context.xml(如果沒有則建立),編輯內容如下:

代碼1.11 /META-INF/context.xml


或修改Tomcat全域的conf/context.xml,修改內容如下:

程式碼1.12  context.xml

#

   

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


注意:此配置只是禁止Session使用Cookie作為識別標誌,並不能阻止其他的Cookie讀寫。也就是說伺服器不會自動維護名為JSESSIONID的Cookie了,但是程式中仍然可以讀寫其他的Cookie。

方  法  名字

描述

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屬性

    "> 
    Home< /a>

    co=#> Homepage

以上是Cookie/Session機制介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn