轉(zhuǎn)自:https://www.cnblogs.com/bellkosmos/p/5237146.html
引子:
最近在好好了解http隙咸,發(fā)現(xiàn)對(duì)介紹http的第一句話【http協(xié)議是無(wú)狀態(tài)的沐悦,無(wú)連接的】就無(wú)法理解了:無(wú)狀態(tài)的【狀態(tài)】到底指的是什么?五督!
找了很多資料不僅沒(méi)有發(fā)現(xiàn)有一針見(jiàn)血正面回答這個(gè)問(wèn)題的藏否,而且有些解釋還充斥了各種錯(cuò)誤,看著看著就覺(jué)得心里憋著一股濁氣吐不出來(lái)
于是在看了很多資料之后充包,我一口吐出濁氣副签,大聲正面提出這個(gè)問(wèn)題:http協(xié)議無(wú)狀態(tài)中的【狀態(tài)】到底指的是什么?!
然后開始不斷探索解決這個(gè)問(wèn)題淆储。冠场。。
最終很高興的是我找到了讓人滿意的答案本砰,先賣個(gè)關(guān)子慈鸠,各位如果著急可以直接拉到最下查看
正文:http協(xié)議無(wú)狀態(tài)中的【狀態(tài)】到底指的是什么?灌具!
先來(lái)看這句話的另外兩個(gè)概念:(標(biāo)準(zhǔn)的http協(xié)議是無(wú)狀態(tài)的青团,無(wú)連接的)
標(biāo)準(zhǔn)的http協(xié)議指的是不包括cookies, session,application的http協(xié)議咖楣,他們都不屬于標(biāo)準(zhǔn)協(xié)議督笆,雖然各種網(wǎng)絡(luò)應(yīng)用提供商,實(shí)現(xiàn)語(yǔ)言诱贿、web容器等娃肿,都默認(rèn)支持它
無(wú)連接指的是什么
每一個(gè)訪問(wèn)都是無(wú)連接,服務(wù)器挨個(gè)處理訪問(wèn)隊(duì)列里的訪問(wèn)珠十,處理完一個(gè)就關(guān)閉連接料扰,這事兒就完了,然后處理下一個(gè)新的
無(wú)連接的含義是限制每次連接只處理一個(gè)請(qǐng)求焙蹭。服務(wù)器處理完客戶的請(qǐng)求晒杈,并收到客戶的應(yīng)答后,即斷開連接
對(duì)于【無(wú)狀態(tài)】孔厉,我看到很多隔著一層磨砂玻璃一樣的模糊說(shuō)法(官方或者教程里的說(shuō)法)拯钻,看著非常難受(但其實(shí)算是對(duì)的)(后來(lái)我發(fā)現(xiàn)我為什么覺(jué)得它看著難受了,因?yàn)樗麄円肓撕芏嘈碌淖颍颐黠@是一個(gè)可能用在很多地方的廣義名詞粪般,這些詞最大的作用就是,混淆概念污桦,下面我標(biāo)注了)
協(xié)議對(duì)于事務(wù)處理沒(méi)有記憶能力【事物處理】【記憶能力】
對(duì)同一個(gè)url請(qǐng)求沒(méi)有上下文關(guān)系【上下文關(guān)系】
每次的請(qǐng)求都是獨(dú)立的亩歹,它的執(zhí)行情況和結(jié)果與前面的請(qǐng)求和之后的請(qǐng)求是無(wú)直接關(guān)系的,它不會(huì)受前面的請(qǐng)求應(yīng)答情況直接影響凡橱,也不會(huì)直接影響后面的請(qǐng)求應(yīng)答情況【無(wú)直接聯(lián)系】【受直接影響】
服務(wù)器中沒(méi)有保存客戶端的狀態(tài)小作,客戶端必須每次帶上自己的狀態(tài)去請(qǐng)求服務(wù)器【狀態(tài)】
我必須得到確切而具體的解釋!
這幾點(diǎn)給了我下一步思考的方向:
【服務(wù)器中沒(méi)有保存客戶端的狀態(tài)梭纹,客戶端必須每次帶上自己的狀態(tài)去請(qǐng)求服務(wù)器 】這里的客戶端的狀態(tài)是不是確切地指服務(wù)器沒(méi)有保存客戶的信息呢躲惰?但顯然不是啊
【HTTP無(wú)狀態(tài)的特性嚴(yán)重阻礙了這些應(yīng)用程序的實(shí)現(xiàn),畢竟交互是需要承前啟后的变抽,簡(jiǎn)單的購(gòu)物車程序也要知道用戶到底在之前選擇了什么商品】我對(duì)此質(zhì)疑為什么無(wú)狀態(tài)就不能實(shí)現(xiàn)購(gòu)物車呢础拨?服務(wù)器就不能存儲(chǔ)東西了么氮块?
【 每次的請(qǐng)求都是獨(dú)立的,<它的執(zhí)行情況和結(jié)果>與<前面的請(qǐng)求>和<之后的請(qǐng)求>是無(wú)直接關(guān)系的】我覺(jué)得這個(gè)說(shuō)法比較靠譜诡宗,但是所謂的不同請(qǐng)求間的沒(méi)有關(guān)系滔蝉,是指的請(qǐng)求內(nèi)容沒(méi)有關(guān)系,還是只是指請(qǐng)求本身沒(méi)有關(guān)系塔沃?
請(qǐng)求內(nèi)容沒(méi)有關(guān)系只可能是服務(wù)器上不存有用戶數(shù)據(jù)才可能啊蝠引,但是顯然是存有的啊
請(qǐng)求本身沒(méi)有關(guān)系,這又有什么意義呢蛀柴,每一次的請(qǐng)求有什么價(jià)值螃概?
根據(jù)這個(gè)方向我做了一個(gè)模擬訪問(wèn)實(shí)驗(yàn):假如沒(méi)有cookie沒(méi)有session,只有http的時(shí)候鸽疾,那當(dāng)一個(gè)注冊(cè)用戶訪問(wèn)這個(gè)購(gòu)物網(wǎng)站的時(shí)候吊洼,會(huì)發(fā)生這些事情:
前提情況:
服務(wù)器肯定為每個(gè)注冊(cè)用戶建立了數(shù)據(jù)表,記錄用戶的數(shù)據(jù)
http是無(wú)連接的
第一步需要登錄
用戶通過(guò)http把用戶的用戶名和密碼發(fā)送給服務(wù)器制肮,服務(wù)器把他們跟自己存有的用戶資料對(duì)比冒窍,如果一致,則返回信息登錄成功
然后用戶點(diǎn)擊某一商品頁(yè)
這個(gè)動(dòng)作相當(dāng)于輸入一個(gè)商品頁(yè)的網(wǎng)址
假如商品頁(yè)比較機(jī)密不對(duì)外公開豺鼻,需要是用戶才能訪問(wèn)
而雖然http能傳送用戶名和密碼综液,而且剛才也輸入了,還驗(yàn)證成功了儒飒,但是因?yàn)榉?wù)器既不會(huì)記得你登錄的狀態(tài)谬莹,你的客戶端也不會(huì)存儲(chǔ)你剛才輸入的用戶名和密碼
所以因?yàn)檫@一次訪問(wèn)因?yàn)闊o(wú)法確定你的身份,只能訪問(wèn)失敗
這時(shí)候如果要解決這個(gè)問(wèn)題约素,而且沒(méi)有cookie沒(méi)有session届良,那就只能你在訪問(wèn)網(wǎng)址的同時(shí)繼續(xù)帶上你的用戶名和密碼(繼續(xù)輸入咯)其實(shí)就像我現(xiàn)在的APP一樣
假設(shè)上一步的問(wèn)題解決了,就是每次訪問(wèn)的時(shí)候都會(huì)手動(dòng)輸入用戶名和密碼圣猎,然后現(xiàn)在的情況是:你已經(jīng)選了幾件商品在你的購(gòu)物車中,你想再添加一件商品乞而,于是你點(diǎn)擊某個(gè)商品旁邊的加號(hào)
這個(gè)動(dòng)作也相當(dāng)于輸入一個(gè)網(wǎng)址送悔,網(wǎng)址的內(nèi)容是發(fā)送一個(gè)請(qǐng)求,往你的購(gòu)物車中加入這個(gè)商品
系統(tǒng)首先用你傳來(lái)的用戶名和密碼驗(yàn)證你的身份爪模,然后訪問(wèn)你的數(shù)據(jù)庫(kù)欠啤,在其中的購(gòu)物車屬性下加一條數(shù)據(jù),就是這個(gè)商品的數(shù)據(jù)
操作結(jié)束后屋灌,返回操作成功洁段,并結(jié)束訪問(wèn)
OK,實(shí)驗(yàn)結(jié)束共郭,看似沒(méi)有cookie沒(méi)有session也能湊合解決問(wèn)題祠丝,其實(shí)兩個(gè)操作都有很大的問(wèn)題
你每訪問(wèn)一次需要權(quán)限的內(nèi)容都需要在客戶端輸入用戶名和密碼疾呻,這一項(xiàng)的繁瑣就不必贅述了
你的每一次操作都要與系統(tǒng)底層的數(shù)據(jù)庫(kù)進(jìn)行交互
多次少量的訪問(wèn)存在非常大的性能浪費(fèi)。非常容易就能想到肯定是一次大量的操作更加有效率写半,于是就想到了緩存區(qū)
你的非重要瑣碎數(shù)據(jù)也被寫進(jìn)數(shù)據(jù)庫(kù)中岸蜗,跟你的主要數(shù)據(jù)放在一起
一次次添加和刪除購(gòu)物車其實(shí)只是跟你這次瀏覽,或者叫這次會(huì)話有關(guān)叠蝇,是臨時(shí)的數(shù)據(jù)璃岳,跟用戶的主要信息無(wú)關(guān),它們沒(méi)什么價(jià)值悔捶,純粹的冗余數(shù)據(jù)(不排除現(xiàn)在有的公司覺(jué)得這種數(shù)據(jù)也有非常大的價(jià)值可以讓它們巧妙的利用)铃慷,用什么存放這些臨時(shí)的數(shù)據(jù),我們也很容易想到緩存區(qū)
經(jīng)過(guò)這個(gè)模擬訪問(wèn)實(shí)驗(yàn)蜕该,結(jié)合前面的思考方向犁柜,我們知道了三點(diǎn):
服務(wù)器上肯定存有用戶的數(shù)據(jù),你提交的增刪改查它也能夠處理蛇损,所以這句話中【服務(wù)器中沒(méi)有保存客戶端的狀態(tài)】的狀態(tài)并不是指用戶的數(shù)據(jù)赁温,我們的猜測(cè)不對(duì)
我們的質(zhì)疑對(duì)了,無(wú)狀態(tài)能實(shí)現(xiàn)購(gòu)物車淤齐,可以通過(guò)服務(wù)器上存有的用戶數(shù)據(jù)來(lái)實(shí)現(xiàn)
但是股囊,使用上面這種方式實(shí)現(xiàn)購(gòu)物車,存在三個(gè)比較大的問(wèn)題更啄。由此稚疹,我們不禁會(huì)想,這三個(gè)問(wèn)題的解決是不是跟我們不確切了解的【狀態(tài)】一詞有關(guān)祭务?于是内狗,接下來(lái)我們來(lái)通過(guò)解決這三個(gè)問(wèn)題來(lái)把【狀態(tài)】的意義探尋下去
由上所述,我們可以在http的基礎(chǔ)上增加一些機(jī)制來(lái)解決上面出現(xiàn)的三個(gè)問(wèn)題
在用戶端增加一個(gè)記錄本是非常有必要的义锥,正好官方加入的cookie機(jī)制跟這個(gè)一樣柳沙,它的用處也確實(shí)是上面討論的那樣,一般就是用來(lái)標(biāo)識(shí)訪問(wèn)者的身份
在服務(wù)器增加一個(gè)緩存區(qū)能同時(shí)解決后兩個(gè)問(wèn)題
有了這個(gè)緩存區(qū)作為一個(gè)數(shù)據(jù)緩沖拌倍,就不用一次次地訪問(wèn)數(shù)據(jù)庫(kù)赂鲤,浪費(fèi)大量計(jì)算機(jī)資源,而是在最后統(tǒng)一歸入數(shù)據(jù)庫(kù)
有了這個(gè)緩存區(qū)柱恤,你就不用把臨時(shí)的數(shù)據(jù)放到數(shù)據(jù)庫(kù)中了数初,只需要在你們交流告一段落之后,再把數(shù)據(jù)整理梗顺,把有用的數(shù)據(jù)歸入數(shù)據(jù)庫(kù)
這里就自然引申出了一個(gè)重要的概念:會(huì)話泡孩,它作為一個(gè)緩沖存儲(chǔ)區(qū)被從數(shù)據(jù)庫(kù)中分離出來(lái),理由并不生硬寺谤,它有其獨(dú)特的重要且不可替代的作用仑鸥。這個(gè)東西恰好跟官方加入的session機(jī)制一樣
另外說(shuō)一個(gè)非常具有迷惑性的容易讓人對(duì)session的主要作用產(chǎn)生偏離的理解:認(rèn)為session存在的價(jià)值就是給訪問(wèn)者分配一個(gè)sessionID代替用戶名和密碼吮播,
為什么非常具有迷惑性,因?yàn)閟ession確實(shí)做了這件事锈候,而且也起到了很大的作用薄料,所以它是對(duì)的,但是只對(duì)一半泵琳,而且沒(méi)有涉及問(wèn)題的本質(zhì)摄职,這種情況是最危險(xiǎn)的(看似很有說(shuō)服力,把你說(shuō)服了获列,所以你很難有動(dòng)力繼續(xù)找下去谷市,但是真實(shí)情況跟它有偏差,但是偏差不大击孩,所以又很難把你說(shuō)服回來(lái)迫悠,只有隱隱的不對(duì)勁,這個(gè)時(shí)候你離真實(shí)最近巩梢,也離真實(shí)最遠(yuǎn))
那就順便說(shuō)說(shuō)它為什么是對(duì)的创泄,也就是用session做的另一件有用的事:
給每個(gè)session一個(gè)ID,一方面用來(lái)方便自己查詢括蝠,另一方面把這個(gè)ID給用戶鞠抑,用戶下一次訪問(wèn)的時(shí)候就可以不用用戶名和密碼,而是直接使用這個(gè)ID來(lái)表明自己的身份
首先忌警,這個(gè)ID安全嗎搁拙?這個(gè)ID比直接傳用戶名和密碼安全嗎?
你很容易會(huì)想到法绵,本來(lái)用戶名和密碼的組合還特地設(shè)置地比較復(fù)雜箕速,你這換一組數(shù)字就代替了,是不是太不安全了朋譬?
我們知道http協(xié)議本身是完全不加密的盐茎,如果使用用戶名和密碼,第一次訪問(wèn)是放在http頭中徙赢,后邊自動(dòng)保存了密碼就會(huì)放在cookie中庭呜,這些都完全沒(méi)有加密,它的安全性基本為0犀忱,就是裸奔了,只要被竊取扶关,那就丟失了
所以阴汇,就這個(gè)意義來(lái)講,sessionID的安全性跟使用用戶名和密碼沒(méi)什么區(qū)別
但是其實(shí)节槐,雖然http本身不能加密搀庶,但是有些軟件什么的拐纱,能在應(yīng)用層面手動(dòng)給你加密,比如QQ就會(huì)使用戶名密碼加臨時(shí)驗(yàn)證碼聯(lián)合哈希哥倔,sessionID加一個(gè)時(shí)間戳簡(jiǎn)單加密也是非常常用的方法
而且因?yàn)閟essionID本身有有效期秸架,即使丟了,也可能很快失效咆蒿,造成的損失可能沒(méi)那么大东抹,而用戶名跟密碼丟了,那就大了
所以總結(jié)就是:
不嚴(yán)格加密的sessionID和用戶名和密碼一樣沃测,都不太安全
但是相比較來(lái)說(shuō)缭黔,sessionID要安全一些
而使用https是完全安全的
然后,使用sessionID有哪些好處
方便直接根據(jù)ID查詢用戶對(duì)應(yīng)的session
加密的時(shí)候計(jì)算量小
安全性不會(huì)降低蒂破,甚至還更高一些
OK馏谨,通過(guò)獨(dú)立地解決純http機(jī)制會(huì)產(chǎn)生的問(wèn)題,我們探討了cookie和session機(jī)制的本質(zhì)附迷。而且想到:【使用http協(xié)議惧互,服務(wù)器中不會(huì)保存客戶端的狀態(tài)】所產(chǎn)生的問(wèn)題通過(guò)增加cookie和session機(jī)制解決了,是不是就意味著這個(gè)【狀態(tài)】跟cookie和session的關(guān)系非常緊密喇伯?所以這個(gè)無(wú)狀態(tài)指的是【沒(méi)有對(duì) 本次會(huì)話 設(shè)置一個(gè)緩存區(qū)喊儡,記錄這次會(huì)話的狀態(tài),緩存區(qū)包括服務(wù)器端和用戶端】但好像還是沒(méi)有點(diǎn)破關(guān)鍵(主要是覺(jué)得跟前面那些官方對(duì)狀態(tài)的說(shuō)法不太吻合艘刚,甚至沒(méi)有對(duì)應(yīng)關(guān)系)
忽然我想到一個(gè)問(wèn)題:一個(gè)有狀態(tài)的http是什么樣的管宵?
很難直接想象有狀態(tài)的http是什么樣,因?yàn)閔ttp這種機(jī)制是天然無(wú)狀態(tài)的
那就類比一下吧攀甚,另一個(gè)天然有狀態(tài)的機(jī)制叫TCP
如果有狀態(tài)的意思是它的每次請(qǐng)求是有聯(lián)系的箩朴,那么有狀態(tài)的TCP的樣子是:假如一份數(shù)據(jù)分了三份TCP包發(fā)送,那這個(gè)包上面會(huì)標(biāo)明這是第幾個(gè)包秋度,會(huì)標(biāo)明這個(gè)包跟那幾個(gè)包是有聯(lián)系的炸庞,有什么聯(lián)系
但好像這個(gè)有狀態(tài)的TCP跟我們想要的有狀態(tài)的HTTP沒(méi)有關(guān)系,因?yàn)榧词姑看蝖ttp請(qǐng)求之間互相有聯(lián)系荚斯,它也不能解決上面提到的http無(wú)狀態(tài)的問(wèn)題
誒埠居,等等,好像能類比:
假如每個(gè)http連接都有一個(gè)簽名事期,于是第一次登陸成功之后滥壕,服務(wù)器就知道了這個(gè)簽名是允許登陸的,于是之后所有同樣簽名的http連接都能登陸兽泣,這里利用了同一個(gè)用戶發(fā)出的http連接之間的同主人關(guān)系绎橘,這里解決了一個(gè)保持登錄狀態(tài)的問(wèn)題
同樣,來(lái)嘗試?yán)眠@個(gè)【每次http請(qǐng)求之間互相有聯(lián)系】來(lái)解決上面碰到的那個(gè)問(wèn)題【每一次操作都要與系統(tǒng)底層的數(shù)據(jù)庫(kù)進(jìn)行交互】唠倦,但想了半天確實(shí)無(wú)法進(jìn)行下去
不過(guò)我靈機(jī)一動(dòng)称鳞,從另一個(gè)角度來(lái)想涮较,好像解決了這個(gè)問(wèn)題:
只有【每次http請(qǐng)求之間互相有聯(lián)系】這個(gè)條件,無(wú)法解決【每一次操作都要與系統(tǒng)底層的數(shù)據(jù)庫(kù)進(jìn)行交互】
因?yàn)楹苊黠@冈止,要解決【每一次操作都要與系統(tǒng)底層的數(shù)據(jù)庫(kù)進(jìn)行交互】就必須在服務(wù)器端開辟一塊緩存區(qū)
不過(guò)如果你思考一下如何實(shí)現(xiàn)【每次http請(qǐng)求之間互相有聯(lián)系】狂票,你就會(huì)發(fā)現(xiàn),它也需要在服務(wù)器端開辟一塊緩存區(qū)
所以【在服務(wù)器端開辟一塊緩存區(qū)】才是真正的條件熙暴,也就是說(shuō)闺属,它確實(shí)等價(jià)于【有狀態(tài)】
而且我也找到了這個(gè)【在服務(wù)器端開辟一塊緩存區(qū)】的條件跟前面那些官方對(duì)狀態(tài)的說(shuō)法對(duì)應(yīng)的點(diǎn),那就是:
通過(guò)在服務(wù)器端開辟一塊緩存區(qū)怨咪,存儲(chǔ)屋剑、記憶刻像、共享一些臨時(shí)數(shù)據(jù)贮乳,你就可以:
協(xié)議對(duì)于事務(wù)處理有記憶能力【事物處理】【記憶能力】
對(duì)同一個(gè)url請(qǐng)求有上下文關(guān)系【上下文關(guān)系】
每次的請(qǐng)求都是不獨(dú)立的鞠评,它的執(zhí)行情況和結(jié)果與前面的請(qǐng)求和之后的請(qǐng)求是直接關(guān)系的【不獨(dú)立】【直接關(guān)系】
服務(wù)器中保存客戶端的狀態(tài)【狀態(tài)】
所以稍浆,這個(gè)狀態(tài)妻怎,加上前面說(shuō)的客戶端也有cookie画机,就是指缨硝,客戶端和服務(wù)器在臨時(shí)會(huì)話中產(chǎn)生的數(shù)據(jù)狐史!而前面也說(shuō)道了芋簿,使用緩存區(qū)保存臨時(shí)會(huì)話中的數(shù)據(jù)是多么重要
所以狀態(tài)不僅包括不同URL訪問(wèn)之間的關(guān)系峡懈,還有對(duì)其他URL訪問(wèn)的數(shù)據(jù)記錄,還有一些其他的東西与斤,所以更確切地說(shuō)肪康,狀態(tài)應(yīng)該是【實(shí)現(xiàn)了這些東西所憑借的后面的緩存空間】中的客戶的臨時(shí)數(shù)據(jù)
cookie和session應(yīng)該是完全實(shí)現(xiàn)了有狀態(tài)這個(gè)功能
一種常見(jiàn)的對(duì)狀態(tài)的誤解:
有人在解釋HTTP的無(wú)狀態(tài)時(shí),把它跟有連接對(duì)立撩穿,說(shuō)是兩種方式磷支,也就是如果想不無(wú)狀態(tài),就必須有連接食寡,但其實(shí)不然
有連接和無(wú)連接以及之后的Keep-Alive都是指TCP連接
有狀態(tài)和無(wú)狀態(tài)可以指TCP也可以指HTTP
TCP一直有狀態(tài)雾狈,HTTP一直無(wú)狀態(tài),但是應(yīng)用為了有狀態(tài)抵皱,就給HTTP加了cookie和session機(jī)制善榛,讓使用http的應(yīng)用也能有狀態(tài),但http還是無(wú)狀態(tài)
開始TCP是有連接呻畸,后來(lái)TCP無(wú)連接移盆,再后來(lái)也就是現(xiàn)在TCP是Keep-Alive,有點(diǎn)像有連接