## **cookie機制:**
* 在程序中,會話跟蹤是很重要的事情。理論上,一個用戶的所有請求操作都應該屬于同一個會話,而另一個用戶的所有請求操作則應該屬于另一個會話,二者不能混淆。例如,用戶A在超市購買的任何商品都應該放在A的購物車內,不論是用戶A什么時間購買的,這都是屬于同一個會話的,不能放入用戶B或用戶C的購物車內,這不屬于同一個會話。
* 而Web應用程序是使用HTTP協議傳輸數據的。HTTP協議是無狀態的協議。一旦數據交換完畢,客戶端與服務器端的連接就會關閉,再次交換數據需要建立新的連接。這就意味著服務器無法從連接上跟蹤會話。即用戶A購買了一件商品放入購物車內,當再次購買商品時服務器已經無法判斷該購買行為是屬于用戶A的會話還是用戶B的會話了。要跟蹤該會話,必須引入一種機制。
* Cookie就是這樣的一種機制。它可以彌補HTTP協議無狀態的不足。在Session出現之前,基本上所有的網站都采用Cookie來跟蹤會話。
* 如果你把Cookies看成為http協議的一個擴展的話,理解起來就容易的多了,其實本質上cookies就是http的一個擴展。有兩個http頭部是專門負責設置以及發送cookie的,它們分別是Set-Cookie以及Cookie。當服務器返回給客戶端一個http響應信息時,其中如果包含Set-Cookie這個頭部時,意思就是指示客戶端建立一個cookie,并且在后續的http請求中自動發送這個cookie到服務器端,直到這個cookie過期。如果cookie的生存時間是整個會話期間的話,那么瀏覽器會將cookie保存在內存中,瀏覽器關閉時就會自動清除這個cookie。另外一種情況就是保存在客戶端的硬盤中,瀏覽器關閉的話,該cookie也不會被清除,下次打開瀏覽器訪問對應網站時,這個cookie就會自動再次發送到服務器端。一個cookie的設置以及發送過程分為以下四步:
```
客戶端發送一個http請求到服務器端
服務器端發送一個http響應到客戶端,其中包含Set-Cookie頭部
客戶端發送一個http請求到服務器端,其中包含Cookie頭部
服務器端發送一個http響應到客戶端
```

## **一、什么是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的內容,如圖所示。


這些都是經過加密處理的,只認出來一個uid別的..搞不出來...求在座大佬解釋一下...
## **二、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。
## **三、Unicode編碼:保存中文**
* 中文與英文字符不同,中文屬于Unicode字符,在內存中占4個字符,而英文屬于ASCII字符,內存中只占2個字節。Cookie中使用Unicode字符時需要對Unicode字符進行編碼,否則會亂碼。
* 提示:Cookie中保存中文只能編碼。一般使用UTF-8編碼即可。不推薦使用GBK等中文編碼,因為瀏覽器不一定支持,而且JavaScript也不支持GBK編碼。
## **四、BASE64編碼:保存二進制圖片**
* Cookie不僅可以使用ASCII字符與Unicode字符,還可以使用二進制數據。例如在Cookie中使用數字證書,提供安全度。使用二進制數據時也需要進行編碼。
* 注意:本程序僅用于展示Cookie中可以存儲二進制內容,并不實用。由于瀏覽器每次請求服務器都會攜帶Cookie,因此Cookie內容不宜過多,否則影響速度。Cookie的內容應該少而精。
## **五、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是否過期。
## **session機制**
* 除了使用Cookie,Web應用程序中還經常使用Session來記錄客戶端狀態。Session是服務器端使用的一種記錄客戶端狀態的機制,使用上比Cookie簡單一些,相應的也增加了服務器的存儲壓力。
* Session技術則是服務端的解決方案,它是通過服務器來保持狀態的。由于Session這個詞匯包含的語義很多,因此需要在這里明確一下 Session的含義。
1. 首先,我們通常都會把Session翻譯成**會話**,因此我們可以把客戶端瀏覽器與服務器之間一系列交互的動作稱為一個 Session。從這個語義出發,我們會提到Session持續的時間,會提到在Session過程中進行了什么操作等等;
2. 其次,**Session指的是服務器端為客戶端所開辟的存儲空間,在其中保存的信息就是用于保持狀態**。從這個語義出發,我們則會提到往Session中存放什么內容,如何根據鍵值從 Session中獲取匹配的內容等。
3. 要使用Session,第一步當然是創建Session了。那么*Session在何時創建*呢?當然還是**在服務器端程序運行的過程中創建的**,不同語言實現的應用程序有不同創建Session的方法,而在Java中是通過調用HttpServletRequest的getSession方法(使用true作為參數)創建的。在創建了Session的同時,服務器會為該Session生成唯一的Session id,而這個Session id在隨后的請求中會被用來重新獲得已經創建的Session;**在Session被創建之后,就可以調用Session相關的方法往Session中增加內容了,而這些內容只會保存在服務器中,發到客戶端的只有Session id;當客戶端再次發送請求的時候,會將這個Session id帶上,服務器接受到請求之后就會依據Session id找到相應的Session,從而再次使用之。正式這樣一個過程,用戶的狀態也就得以保持了。**
### **什么是Session**
Session是另一種記錄客戶狀態的機制,保存在服務器上。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了。
* 如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話,那么Session機制就是通過檢查服務器上的“客戶明細表”來確認客戶身份。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記錄客戶賬號信息。 session.jsp:

### **實現用戶登錄**(涉及后端內容)
* [ ] Session對應的類為javax.servlet.http.HttpSession類。每個來訪者對應一個Session對象,所有該客戶的狀態信息都保存在這個Session對象里。Session對象是在客戶端第一次請求服務器的時候創建的。Session也是一種key-value的屬性對,通過getAttribute(Stringkey)和setAttribute(String key,Objectvalue)方法讀寫客戶狀態信息。Servlet里通過request.getSession()方法獲取該客戶的Session
* 程序中Session中直接保存了Person類對象與Date類對象,使用起來要比Cookie方便。當多個客戶端執行程序時,服務器會保存多個客戶端的Session。獲取Session的時候也不需要聲明獲取誰的Session。Session機制決定了當前客戶只會獲取到自己的Session,而不會獲取到別人的Session。各客戶的Session也彼此獨立,互不可見。
**Session的使用比Cookie方便,但是過多的Session存儲在服務器內存中,會對服務器造成壓力。**
### **Session的生命周期**
* Session保存在服務器端。為了獲得更高的存取速度,服務器一般把Session放在內存里。每個用戶都會有一個獨立的Session。如果Session內容過于復雜,當大量客戶訪問服務器時可能會導致內存溢出。因此,Session里的信息應該盡量精簡。
* Session在用戶第一次訪問服務器的時候自動創建。需要注意只有訪問JSP、Servlet等程序時才會創建Session,只訪問HTML、IMAGE等靜態資源并不會創建Session。如果尚未生成Session,也可以使用request.getSession(true)強制生成Session。
* Session生成后,只要用戶繼續訪問,服務器就會更新Session的最后訪問時間,并維護該Session。用戶每訪問服務器一次,無論是否讀寫Session,服務器都認為該用戶的Session“活躍(active)”了一次。
### **session的有效期**
* 由于會有越來越多的用戶訪問服務器,因此Session也會越來越多。為防止內存溢出,服務器會把長時間內沒有活躍的Session從內存刪除。這個時間就是Session的超時時間。如果超過了超時時間沒訪問過服務器,Session就自動失效了。
* Session的超時時間為maxInactiveInterval屬性,可以通過對應的getMaxInactiveInterval()獲取,通過setMaxInactiveInterval(longinterval)修改。
* Session的超時時間也可以在web.xml中修改。另外,通過調用Session的invalidate()方法可以使Session失效。
### **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地址重寫。
### **URL地址重寫**
URL地址重寫是對客戶端不支持Cookie的解決方案。URL地址重寫的原理是將該用戶Session的id信息重寫到URL地址中。服務器能夠解析重寫后的URL獲取Session的id。這樣即使客戶端不支持Cookie,也可以使用Session來記錄用戶狀態。HttpServletResponse類提供了encodeURL(Stringurl)實現URL地址重寫,例如:

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

效果跟response.encodeURL(String url)是一樣的:如果客戶端支持Cookie,生成原URL地址,如果不支持Cookie,傳回重寫后的帶有jsessionid字符串的地址。
# 后面的看不懂了!!!!!這涉及到后端了,原理太深了媽媽呀~~~!
追溯一下原主:[https://www.cnblogs.com/andy-zhou/p/5360107.html#\_caption\_1](https://www.cnblogs.com/andy-zhou/p/5360107.html#_caption_1)