當前位置:才華齋>計算機>php語言>

HTTP會話原理解釋與應用

php語言 閲讀(3.14W)

導語:通過會話管理能夠對會話進行創建、信息存儲、關閉。下面就由小編為大家介紹一下HTTP會話原理解釋與應用,歡迎大家閲讀!

HTTP會話原理解釋與應用

一、什麼是會話

首先解釋一下什麼是會話。在計算機術語中,會話是指一個終端用户與交互系統進行通訊的過程,比如從輸入賬户密碼進入操作系統到退出操作系統就是一個會話過程。會話較多用於網絡上,TCP的三次握手就創建了一個會話,TCP關閉連接就是關閉會話。用平述的語言可以解釋為:你拔打你女友的電話號碼,你女友接聽,然後一翻“親愛的”,直到任何一方掛掉電話,這個過程就是一個會話。你挑逗一隻小狗,它跟你互動,也是會話;它不鳥你,那就不形成會話。

二、什麼是HTTP會話

協議的狀態是指下一次傳輸可以“記住”這次傳輸信息的能力,HTTP是不會為了下一次連接而維護這次連接所傳輸的信息的。從傳統WEB上看:無狀態是指,當瀏覽器發送請求給服務器的時候,服務器響應,但是同一個瀏覽器再發送請求給服務器的時候,他會響應,但是他不知道你就是剛才那個瀏覽器,簡單地説,就是服務器不會去記得你,所以是無狀態協議。本質是:HTTP1.0是短連接的(這裏先忽略HTTP1.1的keep alive吧),請求響應後,斷開了TCP連接,下一次連接與上一次無關。為了識別不同的請求是否來自同一客户,引用HTTP會話機制,即:多次HTTP連接間維護用户與同一用户發出的不同請求之間關聯的情況稱為維護一個會話(session)。通過會話管理對會話進行創建、信息存儲、關閉等。

三、HTTP會話的實現機制

Cookie與session是各種教材,網上文章所介紹到的與HTTP會話相關的兩個內容。這種者較常見的解釋是:cookie存在在瀏覽器,session存儲在服務器中。這種解釋是最顯淺的,很不嚴謹,但又不能説是錯誤。先從cookie談起吧,很久很久以前,為了完成HTTP會話,那些互聯網的設計者們想到了一個辦法,就是在瀏覽器中存儲用户信息,每次請求都向服務端發送這些信息,這樣服務端就知道請求發送者是誰了,就知道應該返回什麼信息給客户了。但是問題很快就出現了,張三冒充李四的名字發送請求給服務器,服務器把李四的相關信息發給了張三。為了安全起見,互聯網老大哥們又想到了一招識別用户身份的辦法,就是把客户信息存儲在服務端(session),一切用户的身份由服務器指定。直到目前,session已成功HTTP會話的主流,應該説是絕對控制的地位。

Session是怎樣做到會話身份識別的呢?首先,用户端向服務端發送一個請求,服務端接收到請求(這裏忽悠無須會話控制的情況)後,初始化會話,生成相應的會話信息,核心是會話ID,把會話ID發送給客户端,客户端接收到這個會話ID,把它存儲起來,下一次發送請求的時候,附帶着這個會話ID一起發送給服務端,服務端只要根據這個會話ID,就知道是誰了。這個會話ID,就像我們的身份證號碼,一直伴隨終生。核心:服務端如何生成這個會話ID,客户端怎樣存儲這個會話ID。

四、如何存儲會話ID(SESSION ID)

服務端存儲會話ID有多種方式,常見的有本地存儲,如:普通文本,文本名就是會話ID。對於文件系統,同一目錄下,同一文件名只允許唯一一個文件,那麼使用會話ID作為文件名是可以做到唯一確定會話的。除了本地文件存儲,還可以使用memcache、redis、或者Mysql之類的數據庫存儲,即使用第三方數據庫進行存儲。只有一個原則:存儲的會話ID必須是唯一的。

客户端收到服務端返回的(或者説服務端下發的)會話ID後,也是像服務端那樣使用文件名作為會話ID存儲會話信息到文本嗎?如果客户端只與同一個服務端(理解為同一個服務端處理程序)進行會話通訊的話,是可行的。但是,HTTP是因萬維網而生的,瀏覽器作為最常見的HTTP客户端,需要訪問各種不同的網站,如果採用會話ID作為文件名,以這樣的文件存在會話信息的話,會出現這樣的情況:N個不同的網站,服務端採用的是相同的會話生成算法,在同一時刻,很可能會生成一樣的會話ID,客户端則無法唯一確定這個會話ID到底是與哪個服務端通訊,也就是客户端“不認得”服務端了,會話就無法完成。如何確定服務端身份?那就是使用“域”,不同的域擁有獨立的會話。客户端以域相關信息作為文件標識符創建會話文件(客户端存儲)對會話信息進行存儲,其中域與會話ID結合就能唯一確定服務端,並且確定會話。那麼,以“域”信息作為文件名的文件中存儲着會話ID等信息。每次請求某個域的服務時,把存儲着的會話ID附帶到請求中發送到服務端。瀏覽器是最常見的HTTP客户端,瀏覽器存儲會話信息,是使用COOKIE文件的,裏面保存着COOKIE信息,而服務端返回的會話ID也存儲在裏面。會話ID存儲在COOKIE文件中是一般情況下的,而COOKIE信息是作為HTTP頭髮送給服務端的,也就是説這種情況下,會話ID是附帶在請求頭中。但是,HTTP請求,除了頭信息,還可以有內容體,必須有URL。那麼,會話ID同樣可以存儲在內容體中或URL中,比如在禁用瀏覽器COOKIE的情況下,也可實現與服務端會話,要麼依賴內容體,要麼依賴URL,常見的是URL中附帶會話ID,這個在PHP等編程語言中較為常見(曾經的歷史上常見,但是會涉及安全或者效率等問題,這裏不詳述)。

粗糙地,可理解為服務端返回給客户端的會話ID是存儲在COOKIE文件中的。COOKIE文件是由瀏覽器管理的,當然在自實現的客户端中,可以通過編程手段實現COOKIE文件管理,即客户端會話的管理。舉例:IOS開發者,可以把HTTP返回的`信息頭存儲到沙盒中進行管理。PHP開發客户端時,可以把信息頭寫到文件中,或第三方服務中,或網絡存儲中等等。

五、會話管理(SESSION)

會話管理包括:會話創建、會話識別、會話信息操作、會話生命週期、會話關閉。

注意:這一節中的服務端會話都看作是開啟的,無特別情況不再交待。

1、會話創建

客户端發起不帶會話ID(SESSION ID)的HTTP請求,服務端認為還沒產生會話,即創建會話,生成會話ID並且在服務器中存儲相關會話信息,並通知客户端已開啟會話。一般情況下,是在返回給客户端的HTTP header中的COOKIE項中附帶上會話ID,形式為:會話標記:會話ID。客户端根據返回的信息頭,設置本地COOKIE值並存儲。

2、會話識別

會話ID是會話的唯一標識符,一個會話ID只會對應一個會話,就像身份證號碼只對應一個人一樣。HTTP中,服務端是被動接受請求的,會話識別也是被動的(觸發式)。服務端不需要知道發送請求的到底是誰,只需要知道對方發送過來的會話ID,把客户端傳過來的會話ID與服務端存儲的會話ID進行匹配。找不到這個會話ID,就認為這個會話是不存在的。

舉例:服務器有個會話ID是“21412545jladfjljljqwr”,映射的值是“名字:張三,性別:男”。客户端只要請求中的會話ID是“21412545jladfjljljqwr”,就識別到這個會話了,能認為這人是張三,而且是男性。如果客户端請求的會話ID是“qwesadfasdfadsfasdf”,即使客户端附帶了信息“名字:張三,性別:男”,服務端都認為不存在此人,不形成會話。就算是李四盜用了張三的會話ID,服務端也會識別這個會話。

可簡單理解為:SESSION只根據SESSION ID建立起會話,是不負責安全校驗的,只負責讓服務端與客户端可以“通話”。

3、會話信息操作

服務端:會話ID映射信息,ID不變,映射的內容可變

客户端:會話ID映射信息,ID不變,映射的內容可變(即存在在COOKIEk中的內容可變)。

服務端與客户端的會話信息只有會話ID是必須相同的,其它會話信息(即會話ID映射的信息)沒有直接關係。

4、會話生命週期

會話從開始到結束就是會話的生命週期。設定一個時間,這個時間內無通訊就清除會話信息,我們就把這個時間叫做會話超時週期。

習慣地,我們把會話超時週期叫做會話的生命週期,其實這是兩個概念。

5、會話關閉

會話關閉,有2種方式。一種是用户主動清除會話信息,另一種是會話超時。會話超時不是守護任務(或自動任務)週期性檢查處理的,而是訪問會話信息時,根據會話信息中的“上一次更新時間”到現在的時間差,與會話週期比較,超出週期的,清除會話信息,即會話關閉。

經典例子:會話過程中,突然斷網。

六、會話校驗與HTTP協議冪等性

HTTP冪等性簡述:

從定義上看,HTTP方法的冪等性是指一次和多次請求某一個資源應該具有同樣的副作用。冪等性屬於語義範疇,正如編譯器只能幫助檢查語法錯誤一樣,HTTP規範也沒有辦法通過消息格式等語法手段來定義它,這可能是它不太受到重視的原因之一。但實際上,冪等性是分佈式系統設計中十分重要的概念,而HTTP的分佈式本質也決定了它在HTTP中具有重要地位。

舉個例子(摘抄網上):假設有一個從賬户取錢的遠程API(可以是HTTP的,也可以不是),我們暫時用類函數的方式記為:bool withdraw(account_id, amount)。請求服務端,減小account_id的amount金額,成功返回true;失敗金額不變,返回false。

如果服務端成功了,並返回true,但網絡中斷,客户端收不到信息,客户端認為取錢失敗,再次請求,服務端再一次扣費。這裏就涉及一個重複請求同一操作的問題了。

要解決這個問題,我們可以把withdraw設計為冪等的。create_ticket的語義是獲取一個服務器端生成的唯一的處理號ticket_id,它將用於標識後續的操作。idempotent_withdraw和withdraw的區別在於關聯了一個ticket_id,一個ticket_id表示的操作至多隻會被處理一次,每次調用都將返回第一次調用時的處理結果。這樣,idempotent_withdraw就符合冪等性了,客户端就可以放心地多次調用。

從上面例子可以看到create_cicket的作用是生成ID識別碼,後續操作均基於此ID。會話ID本質上也是冪等性的,生成ID後,後續操作均帶上ID參數,即建立操作信息與ID的對應關係。上面的例子並不是安全的,只是確保了操作對於同一個人(一次會話過程)是唯一的。同樣,會話ID只作為身份唯一的識別,不是安全的保證。

簡單會話校驗:

一種較簡單的會話校驗是使用令牌,即請求中除了會話ID,至少還攜帶了令牌。服務端對令牌校驗。令牌由服務端根據某種算法生成,令牌校驗也在服務端中處理,客户端只需存儲令牌,在請求中攜帶令牌,令牌生成算法的複雜程度影響令牌校驗的安全性。

舉例:tokenFunc(param,value=’’) 第一個參數為令牌生成參數,第二個參數為Token值。當第二參數為空時,成生Token,返回string;第二個參數不為空時,檢查Token準確性 ,返回bool. 一般不需要解密,只要散列加密即可。PHP代碼如下:

function token($param,$value=’’){

if(!is_string($param){

$param = serialize($param);

}

$token = md5($param.’sault’);

if(!empty($value)){

if($value == $token){

return true;

}else{

return false;

}

}else{

return $token;

}

}

生成令牌:$token = token($session_id);

檢驗令牌:$check = token($session_id,$token);

七、會話原理的應用

瀏覽器默認是開啟Cookie的,瀏覽器發起HTTP請求時,在請求頭中帶有Cookie信息,只要服務端返回Cookie中包含SessionID,在服務端根據Sessionid即實現HTTP會話,此過程對於前端開發者是透明的(即前端開發可以不關心瀏覽器是怎樣與服務端確定會話的)。

除即時通訊,實時動作網遊外,大多APP是使用HTTP協議與服務端通訊的,使用HTTP協議的原因主要是移動網絡環境複雜(容易斷線),並且HTTP協議穿透性強。原生開發的IOS,安卓等APP,與服務端會話,可不使用COOKIE,只需要在請求中攜帶會話ID即可,這在上文已描述。原生APP與內嵌瀏覽器的APP相比:原生實現性能更高,交互效果流暢,用户體驗相對較好,但快速跌代比不上內嵌瀏覽器的APP。手機配置越來越高,內嵌瀏覽器對HTML5支持也越來越好,在性能要求不是很高的場景,內嵌WEB的性能已可滿足,在佈局多變,或者元素多變的情況下,可快速修改,而無需用户升級APP,也能獲得更好的產品體驗。APP內嵌WEB最常見的場景就是電商APP了,登陸、註冊、入口等交互效果較多的模塊使用原生程序開發,而商品列表、商品展示等等模塊可採用內嵌WEB,這樣既可滿足快速產品跌代的要求,又可滿足操作的性能要求。

舉例:電商APP入門界面、登陸、註冊是使用原生開發的,登陸後跳轉到商品列表頁(即內嵌WEB),然後下訂單。問題來了,如何使得登陸後跳轉到WEB後,還是登陸狀態(即內嵌WEB與原生程序具有一致的會話)呢?內嵌WEB是不會去取得原生程序所存儲的data的。最簡單直接的辦法就是:登陸成功,服務器返回會話ID與成功信息,跳轉到WEB時,發送的HTTP請求頭中包括COOKIE,會話ID存儲在COOKIE中,這樣之後點擊WEB中的鏈接後向服務端發送的HTTP請求頭,就會攜帶這個COOKIE(會話ID)了。簡單地理解:終端原生程序請求服務端,服務端按普通WEB那樣返回信息,終端原生程序取得HTTP返回頭中的COOKIE信息,保存下來,下一次請求時,攜帶COOKIE信息即可。在瀏覽器中,COOKIE的處理由瀏覽器默認處理,而在原生APP程序中,由開發者寫程序去處理而已。