一、什么是HTTP無狀態?
1.1定義:
HTTP無狀態協議,是指協議對於交互性場景沒有記憶能力。
1.2舉個例子:
在點擊一個純的html網頁,請求獲取服務器的html文件資源時,每次http請求都會返回同樣的信息,因為這個是沒有交互的,每一次的請求都是相互獨立的。第一個請求和第二個請求也沒有先后順序,返回處理哪個,結果都是同樣的資源頁面,因為這種場景是無交互的,無論是什么人請求這個地址,服務器都是返回那個相同的響應。
在無交互場景中上面那樣,當然也不會有太大的問題。但是對於涉及到動態交互的場景,就顯得很尷尬了,何為交互?有來又有往,對於一模一樣的兩個接口,不同的人在請求第二個接口時可能會基於請求第一個接口的結果而有所不同。
1.3具體場景:
現在我們來想一個復雜的場景,如在購物網站上買一個書包,流程如下:
- 輸入賬號密碼登陸 /login 用戶信息
- 選擇一款你喜歡的書包加入到購物車中 /cart 用戶信息,產品信息
- 購買支付 /pay 用戶信息,商品信息,金額信息
所謂的登錄只是驗證你是否是一個合法用戶,若是合法則跳轉到信息的頁面,不合法則告知用戶名密碼錯誤。
但是我們在第一步給服務器發完/login接口后,服務器就忘記了。。。忘記了你這個人,到底有沒有經過認證。
所以在添加商品時/cart 你還是需要將你的賬號密碼和商品信息一起提交給 addCart接口,再讓服務器做驗證。
第三步同理。
1.4存在的問題:
所以我們說涉及到交互時,情形就完全不一樣了,因為這三步是有依賴關系的,第一步驗證登錄者是一個合法用戶,驗證通過給你返回200/OK,但是只要服務器給返回了響應,那么一個http的請求和響應就結束了。服務器怎么知道10秒鍾之前你剛剛登錄過呢?不好意思,服務器不知道你有沒有登陸過,他只是對外提供一個登錄接口,要想證明你是合法用戶必須調/login接口。
第二步,將商品加入到購物車中時,你會調用/cart接口,但是注意,這個行為是和第一步是有關聯關系的,是誰將什么物品加入到購物車中了?這個誰,有沒有在網站上注冊賬號呢,是不是一個合法用戶呢?所以說在添加購物車的時候,我們還需要將賬號密碼再次加入到請求參數中,每做一次操作購物車操作時,都需要再把之前已經傳輸過的賬號密碼,再反反復復的傳輸一遍又一遍,這是因為服務器不知道你是不是在20秒之前剛登陸過。
1.5總結:
上面的無狀態是指的,無登錄狀態,即服務器不知道某個用戶是否已登錄過了。因為愚蠢的服務器不知道客戶端是否已登錄過了,所以每次都要在交互場景(會話)中請求中帶上上一次的請求信息,如賬號、密碼。明明只需要在/login接口中,才需要對比數據庫中的賬號密碼和客戶端傳的是否一致來確定合法性。這下在添加購物車中也需要再一次的進行同樣的重復且沒有必要的操作,即降低了響應速度,又對用戶不友好(因為每次都需要填賬號,密碼)。
缺少狀態意味着如果后續處理需要前面的信息,則它必須重傳,這樣可能導致每次連接傳送的數據量增大。另外人們常說的“會話”概念則是上面的交互行為的另一種表述方式。
二、讓服務器有記憶能力之Cookie、Session
背景:
通過上面我們知道了Http中無狀態是一個什么概念,以及在無狀態情況下,要進行添加購物車功能,所帶來的困難。
前瞻:
客戶端與服務器進行動態交互的Web應用程序出現之后,HTTP無狀態的特性嚴重阻礙了這些應用程序的實現,畢竟交互是需要承前啟后的,簡單的購物車程序也要知道用戶到底在之前選擇了什么商品。於是,兩種用於保持HTTP連接狀態的技術就應運而生了,一個是Cookie,而另一個則是Session。HTTP本身是一個無狀態的連接協議,為了支持客戶端與服務器之間的交互,我們就需要通過不同的技術為交互存儲狀態,而這些不同的技術就是Cookie和Session了。
Cookie
由於HTTP是一種無狀態的協議,服務器單純從網絡連接上無從知道客戶身份。怎么辦呢?就給客戶端們頒發一個通行證吧,每人一個,無論誰訪問都必須攜帶自己通行證。這樣服務器就能從通行證上確認客戶身份了。這就是Cookie的工作原理。
Cookie實際上是一小段的文本信息。客戶端請求服務器,如果服務器需要記錄該用戶狀態,就使用response向客戶端瀏覽器頒發一個Cookie。客戶端瀏覽器會把Cookie保存起來。當瀏覽器再請求該網站時,瀏覽器把請求的網址連同該Cookie一同提交給服務器。服務器檢查該Cookie,以此來辨認用戶狀態。服務器還可以根據需要修改Cookie的內容。
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。
Cookie的一個實例
1.在登錄網站的時候選擇記住密碼
2.點擊之后觀察服務器的相應內容
3.查看Chrome中的Cookie設置
4.觀察服務器返回的Cookie內容
5.再次訪問時,發現不需要輸入密碼即可直接登錄,觀察請求頭信息
Cookie記錄登錄狀態的三個方案
cookie並不是單純為了實現 session機制而生的。而是1993 年,網景公司雇員 Lou Montulli 為了讓用戶在訪問某網站時,進一步提高訪問速度,同時也為了進一步實現個人化網絡,發明了今天廣泛使用的 Cookie。cookie還用一個很廣泛的用途就是記住用戶的登錄賬號和密碼,這樣當用戶以后再次需要登錄同一個網站或系統的時候就不需要再次填寫這兩個字段而是直接點擊“登錄”按鈕就好。這就相當於給了一些“甜頭”給用戶,這就回應了“cookie”這個詞語的字面意思了。
如果用戶是在自己家的電腦上網,登錄時就可以記住他的登錄信息,下次訪問時不需要再次登錄,直接訪問即可。
實現方法是把登錄信息如賬號、密碼等保存在Cookie中,並控制Cookie的有效期,下次訪問時再驗證Cookie中的登錄信息即可。
保存登錄信息有多種方案
-
方案一:最直接的是把用戶名與密碼都保持到Cookie中,下次訪問時檢查Cookie中的用戶名與密碼,與數據庫比較。這是一種比較危險的選擇,一般不把密碼等重要信息保存到Cookie中。
-
方案二:是把密碼加密后保存到Cookie中,下次訪問時解密並與數據庫比較。這種方案略微安全一些。如果不希望保存密碼,還可以把登錄的時間戳保存到Cookie與數據庫中,到時只驗證用戶名與登錄時間戳就可以了。
-
方案三:只在登錄時查詢一次數據庫,以后訪問驗證登錄信息時不再查詢數據庫。實現方式是把賬號按照一定的規則加密后,連同賬號一塊保存到Cookie中。下次訪問時只需要判斷賬號的加密規則是否正確即可。
一和二兩種方案驗證賬號時都要查詢數據庫。
方案三把賬號保存到名為account的Cookie中,把賬號連同密鑰用MD5算法加密后保存到名為ssid的Cookie中。驗證時驗證Cookie中的賬號與密鑰加密后是否與Cookie中的ssid相等。
提示:該加密機制中最重要的部分為算法與密鑰。由於MD5算法的不可逆性,即使用戶知道了賬號與加密后的字符串,也不可能解密得到密鑰。因此,只要保管好密鑰與算法,該機制就是安全的。
Session
由於網頁是一種無狀態的連接程序,因此無法得知用戶的瀏覽狀態。在網上購物的時,把很多商品加入了購物車,而在結賬時網站卻不知道你購物車有哪些物品。為了解決這個問題,服務器端就為特定用戶創建了特定的session,用於標示並跟蹤這個用戶,這樣才知道購物車里有哪些商品。
-
Session是另一種記錄客戶狀態的機制,不同的是Cookie保存在客戶端瀏覽器中,而Session保存在服務器上。
-
客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了。
-
如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話,那么Session機制就是通過檢查服務器上的“客戶明細表”來確認客戶身份。
-
Session相當於程序在服務器上建立的一份客戶檔案,客戶來訪的時候只需要查詢客戶檔案表就可以了。
Session和Cookie的關系
- cookie 是一個實際存在的、具體的東西,http 協議中定義在 header 中的字段。
- session 是一個抽象概念、開發者為了實現中斷和繼續等操作,將client和server之間一對一的交互,抽象為“會話”,進而衍生出“會話狀態”,也就是 session 的概念。
- 即session描述的是一種通訊會話機制,而cookie只是目前實現這種機制的主流方案里面的一個參與者,它一般是用於保存session ID。