HTTP協議本身是無狀態的,這和HTTP最初的設計是相符的,每次請求都是創建一個短連接,發送請求,得到數據后就關閉連接。即每次連接都是獨立的一次連接。
這樣的話,導致的問題就是當我在一個頁面登陸了賬號之后,點擊連接打開的新界面或者關閉后再打開我都需要再次登陸賬號,所以我們需要借助Cookie和Session來記錄網頁的狀態。
Cookie
Cookie,有時也用其復數形式 Cookies。可以簡單的理解為存儲在瀏覽器的文本數據。
Cookie按域名來進行存儲,不同的域名存儲的Cookie相互之間不能訪問時隔絕的。而在當前域名存在Cookie時,每次向服務端進行請求時都會在HTTP請求頭中,把當前域名下的所有Cookie都一起進行提交。這樣服務端就可以獲取當前網站存儲的所有Cookie數據。而服務端在進行返回時也可以在HTTP響應頭中附帶上新的Cookie,瀏覽器接收到返回時,會保存服務端發送的Cookie,這樣下次請求,服務端又可以獲得新發送的Cookie數據。
下面我們來詳細的看看Cookie的一些特性。
不可跨域名
根據Cookie的規范,這是由Cookie的隱私安全機制決定的。隱私安全機制能夠禁止網站非法獲取其他網站的Cookie。不同域名的網站下面的Cookie是互相不能訪問的,你當前在cnblog下,就不能獲取和操作的baidu的Cookie,這是比較好理解的。
域名
正常情況下,同一個一級域名下的兩個二級域名如www.baidu.com和images.baidu.com也不能交互使用Cookie,因為二者的域名並不嚴格相同。
如果想所有baidu.com名下的二級域名都可以使用該Cookie,需要設置Cookie的domain參數為.baidu.com。這樣所有二級三級域名,都可以訪問這個Cookie。
注意:domain參數必須以點(".")開始。
路徑
domain屬性決定運行訪問Cookie的域名,而path屬性決定允許訪問Cookie的路徑。
例如,如果只允許/session/下的程序使用Cookie,可以設定path參數為/session/。
設置為“/”時允許所有路徑使用Cookie。path屬性需要使用符號“/”結尾。
注意:頁面只能獲取它屬於的Path的Cookie。例如/session/test/a.jsp不能獲取到路徑為/session/abc/的Cookie。使用時一定要注意。
有效期
Cookie的maxAge決定着Cookie的有效期,單位為秒(Second)。
如果maxAge屬性為正數,則表示該Cookie會在maxAge秒之后自動失效。瀏覽器會將maxAge為正數的Cookie持久化,即寫到對應的Cookie文件中。無論客戶關閉了瀏覽器還是電腦,只要還在maxAge秒之前,登錄網站時該Cookie仍然有效。
如果maxAge為負數,則表示該Cookie僅在本瀏覽器窗口以及本窗口打開的子窗口內有效,關閉窗口后該Cookie即失效。maxAge為負數的Cookie,為臨時性Cookie,不會被持久化,不會被寫到Cookie文件中。
如果maxAge為0,則表示刪除該Cookie。Cookie機制沒有提供刪除Cookie的方法,因此通過設置該Cookie即時失效實現刪除Cookie的效果。失效的Cookie會被瀏覽器從Cookie文件或者內存中刪除。
Cookie默認的maxAge值為–1。
安全屬性
HTTP協議不僅是無狀態的,而且是不安全的。使用HTTP協議的數據不經過任何加密就直接在網絡上傳播,有被截獲的可能。使用HTTP協議傳輸很機密的內容是一種隱患。如果不希望Cookie在HTTP等非安全協議中傳輸,可以設置Cookie的secure屬性為true。瀏覽器只會在HTTPS和SSL等安全協議中傳輸此類Cookie。
提示:secure屬性並不能對Cookie內容加密,因而不能保證絕對的安全性。如果需要高安全性,需要在程序中對Cookie內容加密、解密,以防泄密。
存儲中文和圖片
中文需要使用escape和unescape兩個方法進行編碼和解碼,否則會出現亂碼。
圖片可以使用Base64編碼為字符串來保存。
瀏覽器發送cookie規則
在發起一個請求時,瀏覽器會選擇什么樣的Cookie數據傳遞到服務端呢?
根據請求url中的域名在cookie列表中找所有與當前域名一樣的cookie,然后再根據指定的路徑進行匹配,如果當前請求在域匹配的基礎上還與路徑匹配那么就會將所有匹配的cookie發送給服務器。
也可以手動指定cookie的適用的域(domain),然后手動指定路徑(path)。
一些需要注意的地方
- 可能會被用戶禁用:Cookie是保存在瀏覽器端的,所以用戶有權利選擇關閉Cookie。
- 存儲大小有限制:不同的瀏覽器都對Cookie的存儲大小有限制,Cookie不宜存儲過多的數據。
- 容易被刪除:用戶可以隨時清空Cookie。
- 安全性不夠高:Cookie是用明文的方式存儲的,不適合保存敏感的數據。
Session
在Web端保存用戶狀態的方式除了Cookie外,還可以使用Session來進行保存,不同的是Cookie保存在瀏覽器,而Session保存在服務端。
Session的存取都只能在服務端進行操作,所以瀏覽器是不能直接對Session的數據進行讀取和操作的(間接當然是可以的,瀏覽器可以發送數據給服務端用來存Session的值,服務端也可以直接把Session的值作為返回值返回到瀏覽器)。
唯一要解決的問題就是,因為每次請求都是獨立的,所以服務端需要知道每次的請求的身份,比如我和李雷同時請求,服務端需要知道那些請求是我的,那些是李雷的。
解決這個問題的方式一般如下:當服務端開始使用Session時,會生成一個guid用來標記本次請求的客戶端,可以把這個guid看做是這個客戶端的id,然后,會把這個guid作為Cookie發送給瀏覽器。瀏覽器會自動保存這個guid,下次客戶端再次請求時,這個Cookie會傳遞給服務端,服務端得到guid后,就可以獲取之前的Session的所有數據了。
示例
下面我們以NodeJS的Express框架為例,來看一下Session的例子。
我們第一次請求時,瀏覽器的請求頭沒有包含任何的Cookie信息,但是服務端的響應頭里包含了一個名為connect.sid的Cookie信息返回到瀏覽器,這個connect.sid就是服務端生成的SessionID。
后續的請求,瀏覽器的請求頭中就會包含名為connect.sid的SessionID,服務端可以知道當前請求的SessionID,就可以獲取前面請求保存的數據了,由於瀏覽器已經有了SessionID,那么本次的服務端響應頭的Cookie就沒有再發送connect.sid到瀏覽器了。
有效期
Session在設定時,都有一個有效時間(這個時間一般都可以配置,不同的語言框架配置方式各異),實際上就是傳遞到瀏覽器的Cookie的有效時間,由於Session一般存放在服務端的內存中,如果不清除則會導致內存占用越來越多,最終整個服務器奔潰。所以服務端會在一定的時間清除過期或者長時間不使用的Session及數據。
URL地址重寫
由於Cookie可以被人為的禁止,必須有其他機制以便在Cookie被禁止時仍然能夠把SessionID傳遞回服務器。經常被使用的一種技術叫做URL重寫,就是把SessionID直接附加在URL路徑的后面,附加方式也有兩種,一種是作為URL路徑的附加信息,表現形式為http://...../xxx;sessionid=ByOK ... 99zWpBng!-145788764,另一種是作為查詢字符串附加在URL后面,表現形式為http://...../xxx?sessionid=ByOK ... 99zWpBng!-145788764
這兩種方式對於用戶來說是沒有區別的,只是服務器在解析的時候處理的方式不同,采用第一種方式也有利於把SessionID的信息和正常程序參數區分開來。