面試官問:Http請求中如何保持狀態(tài)?

這是一個被無數(shù)程序員擼過的問題,卻只有少數(shù)人了解了真相。大體上搜了一下,網(wǎng)上關(guān)于http協(xié)議保持狀態(tài)誤導(dǎo)大家的文章還是有的,比如:有人說利用ViewState,那是asp.net下獨有的東西,請注明“asp.net下如何保持狀態(tài)”!!
關(guān)于用戶認證方案可以查看以前的文章:
程序員過關(guān)斬將--cookie和session的關(guān)系其實很簡單

http協(xié)議相對我們的年齡來說,是一個比較古老的協(xié)議,它的誕生之初是為了能讓人們在互聯(lián)網(wǎng)的領(lǐng)域自由沖浪。到了現(xiàn)代,http協(xié)議不謙虛的講,已經(jīng)成為了分布式網(wǎng)絡(luò)的基礎(chǔ)之一,從最初的1.0版本到現(xiàn)在的2.0乃至研發(fā)中的3.0,它在分布式通信領(lǐng)域已經(jīng)越來越重要。
無論http協(xié)議什么樣的文章,都需要把http大體說上一下,這里就簡單啰嗦幾句

http協(xié)議在報文的編碼方式上采用了文本方式,通信上采用客戶端到服務(wù)器的請求-響應(yīng)方式。
http協(xié)議是基于tcp協(xié)議之上的應(yīng)用層協(xié)議,所以它的傳輸速度注定會收到tcp協(xié)議的約束。有人說http協(xié)議采用文本協(xié)議是一個天大的錯誤,我不這么認為,首先在http協(xié)議被發(fā)明之初,可供的選擇并不多,在當(dāng)時看來,文本協(xié)議已經(jīng)是比較好的選擇了。其次,文本協(xié)議除了在傳輸性能上比二進制方式差一些,其他都還好,尤其是在數(shù)據(jù)的直觀性上,很容易被我們理解。尤其是程序員,在看到http的請求和返回文本內(nèi)容的時候,就可以大體猜出很多東西。
在我看來,http最大的缺陷在于交互中的設(shè)計,換句話說,http的狀態(tài)保持問題,才是在我們平時開發(fā)中面臨的最大問題。http天生是無狀態(tài)的,但這并不意味著不能解決。
為什么我們要保持狀態(tài)呢?根本原因在于現(xiàn)在的互聯(lián)網(wǎng)的交互需求。什么是保持狀態(tài)呢?通俗來講,客戶端發(fā)起的http請求,服務(wù)端需要知道來自于哪個客戶端。設(shè)想,如果沒有狀態(tài),當(dāng)你逛淘寶的時候,剁手下了單,服務(wù)器怎么知道是你下的單呢?如果把你的單發(fā)給別人,你是不是要去罵娘了呢?

說到http保持狀態(tài),我有一點要聲明,http和瀏覽器是有區(qū)別的,瀏覽器只不過是利用http協(xié)議來進行通信,有不少同學(xué)一提到http協(xié)議,就以瀏覽器來舉例,這個是不健全的
http協(xié)議要想保持狀態(tài),無非就是利用http協(xié)議本身定義的那些屬性來實現(xiàn)。比如:Header,Body ......只要服務(wù)器能識別,理論上就可以作為保持狀態(tài)的憑據(jù)

http保持狀態(tài)最簡單并且最粗暴的莫過于直接采用參數(shù)了。服務(wù)器把參數(shù)憑據(jù)通過http協(xié)議下發(fā)給客戶端,客戶端無論存儲到哪,只要下次請求把這個參數(shù)攜帶上,服務(wù)器就可以根據(jù)約定讀取相應(yīng)的參數(shù)來進行識別。
這種方式目前大多數(shù)用來保持那些非敏感信息,比如最常見的分頁參數(shù)
https://www.cnblogs.com/#p2
有人會有疑問?分頁參數(shù)也算是狀態(tài)嗎?雖然大多數(shù)的文章中所說的狀態(tài)是指用戶的登錄狀態(tài),但是從狀態(tài)的抽象定義上來看,分頁也算是一種狀態(tài)的定義。而用戶身份狀態(tài)的保持,由于涉及到隱私,一般不會采用url參數(shù)的方式來維持。

Cookie是http請求中header中的一個屬性,它保存在客戶端。

很多文章里,都說Cookie是服務(wù)端下發(fā)給客戶端的,你們這樣說是不是不太好?Cookie本質(zhì)是上客戶端的東西,客戶端不能自己創(chuàng)建Cookie嗎?客戶端當(dāng)然可以自己創(chuàng)建Cookie!!只不過在用戶進行認證的流程中,標(biāo)識用戶身份的cookie是服務(wù)器下發(fā)的,所以在介紹Cookie本身定義的時候請不要誤導(dǎo)別人。
利用Cookie來保持http的狀態(tài)是現(xiàn)在很常見的解決方案,其中的一個原因是:在瀏覽器中沒有跨域的情況下,瀏覽器會在http請求中自動攜帶cookie,非常方便。在非瀏覽器環(huán)境中,可能需要寫代碼來保證每次都攜帶對應(yīng)的cookie。
服務(wù)端在接收到http請求,解析對應(yīng)的cookie即可得到需要保持的狀態(tài)標(biāo)識。說到服務(wù)端,不少人提到了session會保持http狀態(tài),這是不是又不太好了,首先session本質(zhì)上是一個抽象的概念,其次我們平時所說的用戶信息等session是屬于服務(wù)端的kv數(shù)據(jù),不同的客戶端可以識別不同的session本質(zhì)上也是通過cookie機制來實現(xiàn),我認為那些說session可以保持http狀態(tài)的說法是不明確的。

除了以上兩種方式還有其他方式可以保持http的請求狀態(tài)嗎?當(dāng)然有!!
http狀態(tài)的保持需要客戶端和服務(wù)端同時協(xié)作來保證,如果客戶端上傳了cookie,但是服務(wù)端不能正常解析,這也算不上狀態(tài)的保持。理論上服務(wù)端只要能識別http請求中攜帶的某些數(shù)據(jù),就能達到保持狀態(tài)的目的。
在瀏覽器中,受限于每個瀏覽器的功能,瀏覽器發(fā)送一個http請求,自動攜帶的只有規(guī)定的那些header和body數(shù)據(jù),而多數(shù)header只能攜帶協(xié)議規(guī)定的那些固定值,這也是瀏覽器中要想保持http狀態(tài)方案少的原因之一。body一般用在post的http請求中,所以它的應(yīng)用場景是有限的。
關(guān)于http的header的屬性有很多,有興趣的同學(xué)可以去研究一下。這里提及一個“Authorization”,從字面意思就可以知道它和認證相關(guān),當(dāng)我們要保持http請求中用戶的登錄狀態(tài)時候可以用此字段。那保持其他狀態(tài)是否可以用呢?當(dāng)然可以,header中的那些值本質(zhì)上對于服務(wù)端來說就是kv數(shù)據(jù),這些數(shù)據(jù)用于什么用途,每個業(yè)務(wù)都可以靈活控制。比如:通常情況下,“Authorization”這個header用于用戶認證,那我可不可以用于識別是A頁面還是B頁面呢,當(dāng)然可以,只要客戶端在不同的頁面上傳不同的“Authorization”值,然后服務(wù)端去識別這些值就可以了。
從來沒有人說過http協(xié)議只能用于客戶端和服務(wù)端。服務(wù)端和服務(wù)端通信同樣能夠使用http協(xié)議,而且現(xiàn)在很多分布式系統(tǒng)都是這樣來通信的。至于服務(wù)端和服務(wù)端通信,那http協(xié)議保持狀態(tài)就更加靈活了(這里針對瀏覽器來比較),請求方和接受方可以約定任意的header頭來標(biāo)識狀態(tài),這還要得益于http協(xié)議header頭可以自定義的特性。比如:如果喜歡“XXOO”,完全可以采用“XXOO”的header來標(biāo)識狀態(tài)
Accept:?application/json
Accept-Encoding:?gzip,?deflate,?br
Accept-Language:?
.
.
.
XXOO:10次/天
每個問題的解決方案有很多,沒有完美的方案,只有最適合業(yè)務(wù)場景的方案。認清技術(shù)的本質(zhì),才是我們提高自身技能的捷徑。能力有限,技術(shù)無限,歡迎批評指正!
往期推薦



