天天看點

Java Web(三) 會話機制,Cookie和Session詳解

    很大一部分應該知道什麼是會話機制,也能說的出幾句,我也大概了解一點,但是學了之後幾天不用,立馬忘的一幹二淨,原因可能是沒能好好了解這兩種會話機制,是以會一直遺忘,一直重新回過頭來學習它,今天好好把他總結一下,借鑒該文章中的内容,因為我覺得該篇文章确實寫的很不錯,解答了我很多疑問,特點是對cookie和session的了解,其中的會員卡的例子,真是一針見血的奇效。我按照自己的思路來重新整理一份,給自己以後看。

                                  --WZY

一、會話機制

    Web程式中常用的技術,用來跟蹤使用者的整個會話。常用的會話跟蹤技術是Cookie與Session。Cookie通過在用戶端記錄資訊确定使用者身份,Session通過在伺服器端記錄資訊确定使用者身份。

    一次會話指的是:就好比打電話,A給B打電話,接通之後,會話開始,直到挂斷電話,該次會話就結束了,而浏覽器通路伺服器,就跟打電話一樣,浏覽器A給伺服器發送請求,通路web程式,該次會話就已經接通,其中不管浏覽器發送多少請求(就相當于接通電話後說話一樣),都視為一次會話,直到浏覽器關閉,本次會話結束。其中注意,一個浏覽器就相當于一部電話,如果使用火狐浏覽器,通路伺服器,就是一次會話了,然後打開google浏覽器,通路伺服器,這是另一個會話,雖然是在同一台電腦,同一個使用者在通路,但是,這是兩次不同的會話。

    知道了什麼是會話後,思考一個問題,一個浏覽器通路一個伺服器就能建立一個會話,如果别的電腦,都同時通路該伺服器,就會建立很多會話,就拿一些購物網站來說,我們通路一個購物網站的伺服器,會話就被建立了,然後就點選浏覽商品,對感興趣的商品就先加入購物車,等待一起付賬,這看起來是很普通的操作,但是想一下,如果有很多别的電腦上的浏覽器同時也在通路該購物網站的伺服器,跟我們做類似的操作呢?伺服器又是怎麼記住使用者,怎麼知道使用者A購買的任何商品都應該放在A的購物車内,不論是使用者A什麼時間購買的,不能放入使用者B或使用者C的購物車内的呢?是以就有了cookie和session這兩個技術,就像第一行說的那樣,cookie和session用來跟蹤使用者的整個會話,

    Cookie和Session之間的差別和聯系

      假如一個咖啡店有喝5杯咖啡免費贈一杯咖啡的優惠,然而一次性消費5杯咖啡的機會微乎其微,這時就需要某種方式來紀錄某位顧客的消費數量。想象一下其實也無外乎下面的幾種方案:

      1、該店的店員很厲害,能記住每位顧客的消費數量,隻要顧客一走進咖啡店,店員就知道該怎麼對待了。這種做法就是協定本身支援狀态。但是http協定本身是無狀态的

      2、發給顧客一張卡片,上面記錄着消費的數量,一般還有個有效期限。每次消費時,如果顧客出示這張卡片,則此次消費就會與以前或以後的消費相聯系起來。這種做法就是在用戶端保持狀态。也就是cookie。 顧客就相當于浏覽器,cookie如何工作,下面會詳細講解

      3、發給顧客一張會員卡,除了卡号之外什麼資訊也不紀錄,每次消費時,如果顧客出示該卡片,則店員在店裡的紀錄本上找到這個卡号對應的紀錄添加一些消費資訊。這種做法就是在伺服器端保持狀态。

      由于HTTP協定是無狀态的,而出于種種考慮也不希望使之成為有狀态的,是以,後面兩種方案就成為現實的選擇。具體來說cookie機制采用的是在用戶端保持狀态的方案,而session機制采用的是在伺服器端保持狀态的方案。同時我們也看到,由于采用伺服器端保持狀态的方案在用戶端也需要儲存一個辨別,是以session機制可能需要借助于cookie機制來達到儲存辨別的目的,但實際上它還有其他選擇

二、Cookie

    上面已經介紹了為什麼要使用Cookie,以及Cookie的一些特點,比如儲存在用戶端,用來記錄使用者身份資訊的,現在來看看如何使用Cookie。

     借着上面會員卡的例子來說,采用的是第二種方案,其中還需要解決的問題就是:如何分發會員卡,會員卡的内容,客戶如何使用會員卡,會員卡的有效日期,會員卡的使用範圍

     1、如何分發會員卡、會員卡的内容:也就是cookie是如何建立的?建立後如何發送給用戶端?

        由伺服器進行建立,也就相當于咖啡店來建立會員卡,在建立會員卡的同時,就會将會員卡中的内容也給設定了

          Cookie cookie = new Cookie(key,value);  //以鍵值對的方式存放内容,

          response.addCookie(cookie);  //發送回浏覽器端

        注意:一旦cookie建立好了,就不能在往其中增加别的鍵值對,但是可以修改其中的内容,

          cookie.setValue();  //将key對應的value值修改

     2、客戶如何使用會員卡,cookie在用戶端是如何工作的,工作原理是什麼?

        

        這個過程就相當于,咖啡店建立好了會員卡,并且已經設定了其中的内容,交到了客戶手中,下次客戶過來時,就帶着會員卡過來,就知道你是會員了,然後咖啡店就拿到你的會員卡對其進行操作。

     3、會員卡的有效日期?也就是cookie也是擁有有效日期的。

        這個可以自由設定,預設是關閉浏覽器,cookie就沒用了。

        cookie.setMaxAge(expiry);  //設定cookie被浏覽器儲存的時間。

          expiry:機關秒,預設為-1,

            expiry=-1:代表浏覽器關閉後,也就是會話結束後,cookie就失效了,也就沒有了。

             expiry>0:代表浏覽器關閉後,cookie不會失效,仍然存在。并且會将cookie儲存到硬碟中,直到設定時間過期才會被浏覽器自動删除,

            expiry=0:删除cookie。不管是之前的expiry=-1還是expiry>0,當設定expiry=0時,cookie都會被浏覽器給删除。

    

    4、會員卡的使用範圍?比如星巴克在北京有一個分店,在上海也有一個分店,我們隻是在北京的星巴克辦理了會員卡,那麼當我們到上海時,就不能使用該會員卡進行打折優惠了。而cookie也是如此,可以設定伺服器端擷取cookie的通路路徑,而并非在伺服器端的web項目中所有的servlet都能通路該cookie。

      cookie預設路徑:目前通路的servlet父路徑。

        例如:

http://localhost

:8080/test01/a/b/c/SendCookieServlet

          預設路徑:/test01/a/b/c  也就是說,在該預設路徑下的所有Servlet都能夠擷取到cookie,/test01/a/b/c/MyServlet 這個MyServlet就能擷取到cookie。

      修改cookie的通路路徑

        setPath("/");  //在該伺服器下,任何項目,任何位置都能擷取到cookie,

          通途:保證在tomcat下所有的web項目可以共享相同的cookie

       例如:tieba , wenku , beike 多個項目共享資料。例如使用者名。

        setPath("/test01/");  //在test01項目下任何位置都能擷取到cookie。

    5、總結Cookie:

        工作流程:

          1. servlet建立cookie,儲存少量資料,發送浏覽器。

         2. 浏覽器獲得伺服器發送的cookie資料,将自動的儲存到浏覽器端。

         3. 下次通路時,浏覽器将自動攜帶cookie資料發送給伺服器。
           

        cookie操作

          1.建立cookie:new Cookie(name,value)

         2.發送cookie到浏覽器:HttpServletResponse.addCookie(Cookie)

          3.servlet接收cookie:HttpServletRequest.getCookies() 浏覽器發送的所有cookie

         cookie特點

        1. 每一個cookie檔案大小:4kb , 如果超過4kb浏覽器不識别

          2. 一個web站點(web項目):發送20個

            3.一個浏覽器儲存總大小:300個

            4.cookie 不安全,可能洩露使用者資訊。浏覽器支援禁用cookie操作。

          5. 預設情況生命周期:與浏覽器會話一樣,當浏覽器關閉時cookie銷毀的。---臨時cookie
           

        cookie api

          getName() 獲得名稱,cookie中的key

          getValue() 獲得值,cookie中的value

          setValue(java.lang.String newValue) 設定内容,用于修改key對應的value值。

          setMaxAge(int expiry) 設定有效時間【】

          setPath(java.lang.String uri) 設定路徑【】  

          setDomain(java.lang.String pattern) 設定域名 , 一般無效,有浏覽器自動設定,setDomain(".itheima.com")

             www.itheima.com / bbs.itheima.com 都可以通路

             a.b.itheima.com無法通路

             作用:設定cookie的作用範圍,域名+路徑在一起就構成了cookie的作用範圍,上面單獨設定的setPath有用,是因為有浏覽器自動設定該域名屬性,但是我們必須知道有這麼個屬性進行域名設定的

          isHttpOnly() 是否隻是http協定使用。隻能servlet的通過getCookies()獲得,javascript不能獲得。

          setComment(java.lang.String purpose) (了解)  //對該cookie進行描述的資訊(說明作用),浏覽器顯示cookie資訊時能看到

          setSecure(boolean flag) (了解)  是否使用安全傳輸協定。為true時,隻有當是https請求連接配接時cookie才會發送給伺服器端,而http時不會,但是服務端還是可以發送給浏覽端的。

          setVersion(int v) (了解)  參數為0(傳統Netscape cookie規範編譯)或1(RFC 2109規範編譯)。這個沒用到,不是很懂

        注意:cookie不能發送中文,如果要發送中文,就需要進行特别處理。

          JDK提供工具,進行編碼

            URLEncoder:編碼

            URLDecoder:解碼

            //發送cookie

            Cookie cookie = new Cookie(URLEncoder.encode("哈哈"),URLEncoder.encode("呵呵"));

            response.addCookie(cookie);

            //獲得cookie中文内容

            URLDecoder.decoder(request.getCookie().getName);  //擷取key

            URLDecoder.decoder(request.getCookie().getValue);  //擷取value  

     6.cookie案例

         6.1、記住使用者名

            登入時,在伺服器端擷取到使用者名,然後建立一個cookie,将使用者名存入cookie中,發送回浏覽器端,然後浏覽器下次在通路登入頁面時,先拿到cookie,将cookie中的資訊拿出來,看是否儲存了該使用者名,如果儲存了,那麼直接用他,如果沒有,則自己手寫使用者名。

         6.2、曆史記錄

            比如購物網站,都會有我們的浏覽記錄的,實作原理其實也是用cookie技術,每浏覽一個商品,就将其存入cookie中,到需要顯示浏覽記錄時,隻需要将cookie拿出來周遊即可。  

三、Session

     同樣,會員卡的例子的第三種方法,發給顧客一張會員卡,除了卡号之外什麼資訊也不紀錄,每次消費時,如果顧客出示該卡片,則店員在店裡的紀錄本上找到這個卡号對應的紀錄添加一些消費資訊。這種做法就是在伺服器端保持狀态。 這就是session的用法,在伺服器端來保持狀态,儲存一些使用者資訊。

     功能作用:伺服器用于共享資料技術,

            

     session原理分析:

        首先浏覽器請求伺服器通路web站點時,程式需要為用戶端的請求建立一個session的時候,伺服器首先會檢查這個用戶端請求是否已經包含了一個session辨別、稱為SESSIONID,如果已經包含了一個sessionid則說明以前已經為此用戶端建立過session,伺服器就按照sessionid把這個session檢索出來使用,如果用戶端請求不包含session id,則伺服器為此用戶端建立一個session并且生成一個與此session相關聯的session id,sessionid 的值應該是一個既不會重複,又不容易被找到規律以仿造的字元串,這個sessionid将在本次響應中傳回到用戶端儲存,儲存這個sessionid的方式就可以是cookie,這樣在互動的過程中,浏覽器可以自動的按照規則把這個辨別發回給伺服器,伺服器根據這個sessionid就可以找得到對應的session,又回到了這段文字的開始。

     擷取session:

        request.getSession();  //如果沒有将建立一個新的,等效getSession(true);

          有些人不了解,為什麼是通過request來擷取session,可以這樣了解,在擷取session時,需要檢測請求中是否有session辨別,是以需要用request來擷取

        request.getSession(boolean);  //true:沒有将建立,false:沒有将傳回null

     session屬性操作:

        xxxAttribute(...)

          用來存放一些資訊,然後才能共享資訊 

          setAttrubute(key,value);

          getAttribute(key);

     

     session生命周期

        常常聽到這樣一種誤解“隻要關閉浏覽器,session就消失了”。其實可以想象一下會員卡的例子,除非顧客主動對店家提出銷卡,否則店家絕對不會輕易删除顧客的資料。對session來說也是一樣的,除非程式通知伺服器删除一個session,否則伺服器會一直保留,程式一般都是在使用者做log off的時候發個指令去删除session。然而浏覽器從來不會主動在關閉之前通知伺服器它将要關閉,是以伺服器根本不會有機會知道浏覽器已經關閉,之是以會有這種錯覺,是大部分session機制都使用會話cookie來儲存session id,而關閉浏覽器後這個session id就消失了,再次連接配接伺服器時也就無法找到原來的session。如果伺服器設定的cookie被儲存到硬碟上,或者使用某種手段改寫浏覽器發出的HTTP請求頭,把原來的session id發送給伺服器,則再次打開浏覽器仍然能夠找到原來的session 

        恰恰是由于關閉浏覽器不會導緻session被删除,迫使伺服器為seesion設定了一個失效時間,一般是30分鐘,當距離用戶端上一次使用session的時間超過這個失效時間時,伺服器就可以認為用戶端已經停止了活動,才會把session删除以節省存儲空間

        我們也可以自己來控制session的有效時間

          session.invalidate()将session對象銷毀

          setMaxInactiveInterval(int interval) 設定有效時間,機關秒

          在web.xml中配置session的有效時間

              30 機關:分鐘

        是以,讨論了這麼就,session的生命周期就是:

            建立:第一次調用getSession()

            銷毀:

               1、逾時,預設30分鐘

               2、執行api:session.invalidate()将session對象銷毀、setMaxInactiveInterval(int interval) 設定有效時間,機關秒

               3、伺服器非正常關閉

                  自殺,直接将JVM馬上關閉

                  如果正常關閉,session就會被持久化(寫入到檔案中,因為session預設的逾時時間為30分鐘,正常關閉後,就會将session持久化,等30分鐘後,就會被删除)

                  位置: D:\java\tomcat\apache-tomcat-7.0.53\work\Catalina\localhost\test01\SESSIONS.ser

     session id的URL重寫

        當浏覽器将cookie禁用,基于cookie的session将不能正常工作,每次使用request.getSession() 都将建立一個新的session。達不到session共享資料的目的,但是我們知道原理,隻需要将session id 傳遞給伺服器session就可以正常工作的。

        解決:通過URL将session id 傳遞給伺服器:URL重寫

          手動方式: url;jsessionid=....

          api方式:

               encodeURL(java.lang.String url) 進行所有URL重寫

               encodeRedirectURL(java.lang.String url) 進行重定向 URL重寫 

               這兩個用法基本一緻,隻不過考慮特殊情況,要通路的連結可能會被Redirect到其他servlet去進行處理,這樣你用上述方法帶來的session的id資訊不能被同時傳送到其他servlet.這時候用encodeRedirectURL()方法就可以了 

          如果浏覽器禁用cooke,api将自動追加session id ,如果沒有禁用,api将不進行任何修改。

          注意:如果浏覽器禁用cookie,web項目的所有url都需進行重寫。否則session将不能正常工作

        當禁止了cookie時,

                

四、總結

    知道了什麼是cookie和什麼是session?

       cookie是一種在用戶端記錄使用者資訊的技術,因為http協定是無狀态的,為了解決這個問題而産生了cookie。記錄使用者名等一些應用

       session是一種在服務端記錄使用者資訊的技術,一般session用來在伺服器端共享資料,

    cookie的工作原理?session的工作原理?

       cookie工作原理,可以看上面講解cookie的那張圖,cookie是由伺服器端建立發送回浏覽器端的,并且每次請求伺服器都會将cookie帶過去,以便伺服器知道該使用者是哪一個。其cookie中是使用鍵值對來存儲資訊的,并且一個cookie隻能存儲一個鍵值對。是以在擷取cookie時,是會擷取到所有的cookie,然後從其中周遊。

             

       session的工作原理就是依靠cookie來做支撐,第一次使用request.getSession()時session被建立,并且會為該session建立一個獨一無二的sessionid存放到cookie中,然後發送會浏覽器端,浏覽器端每次請求時,都會帶着這個sessionid,伺服器就會認識該sessionid,知道了sessionid就找得到哪個session。以此來達到共享資料的目的。 這裡需要注意的是,session不會随着浏覽器的關閉而死亡,而是等待逾時時間。

  

      如果對cookie和session還有不了解的地方,用大家肯定都會用,就是需要了解,為什麼需要使用cookie和session,可以看看那個會員卡的例子,cookie和session隻是為了解決http協定無狀态的這種缺陷,為了記錄使用者資訊,記錄浏覽器和伺服器之間的狀态和衍生出來的。