天天看點

http協定無狀态中的【狀态】到底指的是什麼?!對Http協定無狀态的了解

先來看這句話的另外兩個概念:(标準的http協定是無狀态的,無連接配接的)

  1. 标準的http協定指的是不包括cookies, session,application(是手機應用)的http協定,他們都不屬于标準協定,雖然各種網絡應用提供商,實作語言、web容器等,都預設支援它
  2. 無連接配接指的是什麼
    1. 每一個通路都是無連接配接,伺服器挨個處理通路隊列裡的通路,處理完一個就關閉連接配接,這事兒就完了,然後處理下一個新的
    2. 無連接配接的含義是限制每次連接配接隻處理一個請求。伺服器處理完客戶的請求,并收到客戶的應答後,即斷開連接配接

對于【無狀态】,我看到很多隔着一層磨砂玻璃一樣的模糊說法(官方或者教程裡的說法),看着非常難受(但其實算是對的)(後來我發現我為什麼覺得它看着難受了,因為他們引入了很多新的,而且明顯是一個可能用在很多地方的廣義名詞,這些詞最大的作用就是,混淆概念,下面我标注了)

  1. 協定對于事務處理沒有記憶能力【事物處理】【記憶能力】
  2. 對同一個url請求沒有上下文關系【上下文關系】
  3. 每次的請求都是獨立的,它的執行情況和結果與前面的請求和之後的請求是無直接關系的,它不會受前面的請求應答情況直接影響,也不會直接影響後面的請求應答情況【無直接聯系】【受直接影響】
  4. 伺服器中沒有儲存用戶端的狀态,用戶端必須每次帶上自己的狀态去請求伺服器【狀态】

我必須得到确切而具體的解釋!

這幾點給了我下一步思考的方向:

  1. 【伺服器中沒有儲存用戶端的狀态,用戶端必須每次帶上自己的狀态去請求伺服器 】這裡的用戶端的狀态是不是确切地指伺服器沒有儲存客戶的資訊呢?但顯然不是啊
  2. 【HTTP無狀态的特性嚴重阻礙了這些應用程式的實作,畢竟互動是需要承前啟後的,簡單的購物車程式也要知道使用者到底在之前選擇了什麼商品】我對此質疑為什麼無狀态就不能實作購物車呢?伺服器就不能存儲東西了麼?
  3. 【 每次的請求都是獨立的,<它的執行情況和結果>與<前面的請求>和<之後的請求>是無直接關系的】我覺得這個說法比較靠譜,但是所謂的不同請求間的沒有關系,是指的請求内容沒有關系,還是隻是指請求本身沒有關系?
    1. 請求内容沒有關系隻可能是伺服器上不存有使用者資料才可能啊,但是顯然是存有的啊
    2. 請求本身沒有關系,這又有什麼意義呢,每一次的請求有什麼價值?

根據這個方向我做了一個模拟通路實驗:假如沒有cookie沒有session,隻有http的時候,那當一個注冊使用者通路這個購物網站的時候,會發生這些事情:

  1. 前提情況:
    1. 伺服器肯定為每個注冊使用者建立了資料表,記錄使用者的資料
    2. http是無連接配接的
  2. 第一步需要登入
    1. 使用者通過http把使用者的使用者名和密碼發送給伺服器,伺服器把他們跟自己存有的使用者資料對比,如果一緻,則傳回資訊登入成功
  3. 然後使用者點選某一商品頁
    1. 這個動作相當于輸入一個商品頁的網址
    2. 假如商品頁比較機密不對外公開,需要是使用者才能通路
    3. 而雖然http能傳送使用者名和密碼,而且剛才也輸入了,還驗證成功了,但是因為伺服器既不會記得你登入的狀态,你的用戶端也不會存儲你剛才輸入的使用者名和密碼
    4. 是以因為這一次通路因為無法确定你的身份,隻能通路失敗
      1. 這時候如果要解決這個問題,而且沒有cookie沒有session,那就隻能你在通路網址的同時繼續帶上你的使用者名和密碼(繼續輸入咯)其實就像我現在的APP一樣
  4. 假設上一步的問題解決了,就是每次通路的時候都會手動輸入使用者名和密碼,然後現在的情況是:你已經選了幾件商品在你的購物車中,你想再添加一件商品,于是你點選某個商品旁邊的加号
    1. 這個動作也相當于輸入一個網址,網址的内容是發送一個請求,往你的購物車中加入這個商品
    2. 系統首先用你傳來的使用者名和密碼驗證你的身份,然後通路你的資料庫,在其中的購物車屬性下加一條資料,就是這個商品的資料
    3. 操作結束後,傳回操作成功,并結束通路
  5. OK,實驗結束,看似沒有cookie沒有session也能湊合解決問題,其實兩個操作都有很大的問題
    1. 你每通路一次需要權限的内容都需要在用戶端輸入使用者名和密碼,這一項的繁瑣就不必贅述了
    2. 你的每一次操作都要與系統底層的資料庫進行互動
      1. 多次少量的通路存在非常大的性能浪費。非常容易就能想到肯定是一次大量的操作更加有效率,于是就想到了緩存區
    3. 你的非重要瑣碎資料也被寫進資料庫中,跟你的主要資料放在一起
      1. 一次次添加和删除購物車其實隻是跟你這次浏覽,或者叫這次會話有關,是臨時的資料,跟使用者的主要資訊無關,它們沒什麼價值,純粹的備援資料(不排除現在有的公司覺得這種資料也有非常大的價值可以讓它們巧妙的利用),用什麼存放這些臨時的資料,我們也很容易想到緩存區

經過這個模拟通路實驗,結合前面的思考方向,我們知道了三點:

  1. 伺服器上肯定存有使用者的資料,你送出的增删改查它也能夠處理,是以這句話中【伺服器中沒有儲存用戶端的狀态】的狀态并不是指使用者的資料,我們的猜測不對
  2. 我們的質疑對了,無狀态能實作購物車,可以通過伺服器上存有的使用者資料來實作
  3. 但是,使用上面這種方式實作購物車,存在三個比較大的問題。由此,我們不禁會想,這三個問題的解決是不是跟我們不确切了解的【狀态】一詞有關?于是,接下來我們來通過解決這三個問題來把【狀态】的意義探尋下去

由上所述,我們可以在http的基礎上增加一些機制來解決上面出現的三個問題

  1. 在使用者端增加一個記錄本是非常有必要的,正好官方加入的cookie機制跟這個一樣,它的用處也确實是上面讨論的那樣,一般就是用來辨別通路者的身份
  2. 在伺服器增加一個緩存區能同時解決後兩個問題
    1. 有了這個緩存區作為一個資料緩沖,就不用一次次地通路資料庫,浪費大量計算機資源,而是在最後統一歸入資料庫
    2. 有了這個緩存區,你就不用把臨時的資料放到資料庫中了,隻需要在你們交流告一段落之後,再把資料整理,把有用的資料歸入資料庫
  3. 這裡就自然引申出了一個重要的概念:會話,它作為一個緩沖存儲區被從資料庫中分離出來,理由并不生硬,它有其獨特的重要且不可替代的作用。這個東西恰好跟官方加入的session機制一樣
    1. 另外說一個非常具有迷惑性的容易讓人對session的主要作用産生偏離的了解:認為session存在的價值就是給通路者配置設定一個sessionID代替使用者名和密碼,
    2. 為什麼非常具有迷惑性,因為session确實做了這件事,而且也起到了很大的作用,是以它是對的,但是隻對一半,而且沒有涉及問題的本質,這種情況是最危險的(看似很有說服力,把你說服了,是以你很難有動力繼續找下去,但是真實情況跟它有偏差,但是偏差不大,是以又很難把你說服回來,隻有隐隐的不對勁,這個時候你離真實最近,也離真實最遠)
    3. 那就順便說說它為什麼是對的,也就是用session做的另一件有用的事:
      1. 給每個session一個ID,一方面用來友善自己查詢,另一方面把這個ID給使用者,使用者下一次通路的時候就可以不用使用者名和密碼,而是直接使用這個ID來表明自己的身份
      2. 首先,這個ID安全嗎?這個ID比直接傳使用者名和密碼安全嗎?
        1. 你很容易會想到,本來使用者名和密碼的組合還特地設定地比較複雜,你這換一組數字就代替了,是不是太不安全了?
        2. 我們知道http協定本身是完全不加密的,如果使用使用者名和密碼,第一次通路是放在http頭中,後邊自動儲存了密碼就會放在cookie中,這些都完全沒有加密,它的安全性基本為0,就是裸奔了,隻要被竊取,那就丢失了
        3. 是以,就這個意義來講,sessionID的安全性跟使用使用者名和密碼沒什麼差別
        4. 但是其實,雖然http本身不能加密,但是有些軟體什麼的,能在應用層面手動給你加密,比如QQ就會使使用者名密碼加臨時驗證碼聯合哈希,sessionID加一個時間戳簡單加密也是非常常用的方法
        5. 而且因為sessionID本身有有效期,即使丢了,也可能很快失效,造成的損失可能沒那麼大,而使用者名跟密碼丢了,那就大了
        6. 是以總結就是:
          1. 不嚴格加密的sessionID和使用者名和密碼一樣,都不太安全
          2. 但是相比較來說,sessionID要安全一些
          3. 而使用https是完全安全的
      3. 然後,使用sessionID有哪些好處
        1. 友善直接根據ID查詢使用者對應的session
        2. 加密的時候計算量小
        3. 安全性不會降低,甚至還更高一些

OK,通過獨立地解決純http機制會産生的問題,我們探讨了cookie和session機制的本質。而且想到:【使用http協定,伺服器中不會儲存用戶端的狀态】所産生的問題通過增加cookie和session機制解決了,是不是就意味着這個【狀态】跟cookie和session的關系非常緊密?是以這個無狀态指的是【沒有對 本次會話 設定一個緩存區,記錄這次會話的狀态,緩存區包括伺服器端和使用者端】但好像還是沒有點破關鍵(主要是覺得跟前面那些官方對狀态的說法不太吻合,甚至沒有對應關系)

忽然我想到一個問題:一個有狀态的http是什麼樣的?

  1. 很難直接想象有狀态的http是什麼樣,因為http這種機制是天然無狀态的
  2. 那就類比一下吧,另一個天然有狀态的機制叫TCP
    1. 如果有狀态的意思是它的每次請求是有聯系的,那麼有狀态的TCP的樣子是:假如一份資料分了三份TCP包發送,那這個包上面會标明這是第幾個包,會标明這個包跟那幾個包是有聯系的,有什麼聯系
  3. 但好像這個有狀态的TCP跟我們想要的有狀态的HTTP沒有關系,因為即使每次http請求之間互相有聯系,它也不能解決上面提到的http無狀态的問題
  4. 诶,等等,好像能類比:
    1. 假如每個http連接配接都有一個簽名,于是第一次登陸成功之後,伺服器就知道了這個簽名是允許登陸的,于是之後所有同樣簽名的http連接配接都能登陸,這裡利用了同一個使用者發出的http連接配接之間的同主人關系,這裡解決了一個保持登入狀态的問題
    2. 同樣,來嘗試利用這個【每次http請求之間互相有聯系】來解決上面碰到的那個問題【每一次操作都要與系統底層的資料庫進行互動】,但想了半天确實無法進行下去
    3. 不過我靈機一動,從另一個角度來想,好像解決了這個問題:
      1. 隻有【每次http請求之間互相有聯系】這個條件,無法解決【每一次操作都要與系統底層的資料庫進行互動】
      2. 因為很明顯,要解決【每一次操作都要與系統底層的資料庫進行互動】就必須在伺服器端開辟一塊緩存區
      3. 不過如果你思考一下如何實作【每次http請求之間互相有聯系】,你就會發現,它也需要在伺服器端開辟一塊緩存區
      4. 是以【在伺服器端開辟一塊緩存區】才是真正的條件,也就是說,它确實等價于【有狀态】
      5. 而且我也找到了這個【在伺服器端開辟一塊緩存區】的條件跟前面那些官方對狀态的說法對應的點,那就是:
        1. 通過在伺服器端開辟一塊緩存區,存儲、記憶、共享一些臨時資料,你就可以:
          1. 協定對于事務處理有記憶能力【事物處理】【記憶能力】
          2. 對同一個url請求有上下文關系【上下文關系】
          3. 每次的請求都是不獨立的,它的執行情況和結果與前面的請求和之後的請求是直接關系的【不獨立】【直接關系】
          4. 伺服器中儲存用戶端的狀态【狀态】
      6. 是以,這個狀态,加上前面說的用戶端也有cookie,就是指,用戶端和伺服器在臨時會話中産生的資料!而前面也說道了,使用緩存區儲存臨時會話中的資料是多麼重要
        1. 是以狀态不僅包括不同URL通路之間的關系,還有對其他URL通路的資料記錄,還有一些其他的東西,是以更确切地說,狀态應該是【實作了這些東西所憑借的後面的緩存空間】中的客戶的臨時資料
        2. cookie和session應該是完全實作了有狀态這個功能

一種常見的對狀态的誤解:

  1. 有人在解釋HTTP的無狀态時,把它跟有連接配接對立,說是兩種方式,也就是如果想不無狀态,就必須有連接配接,但其實不然
  2. 有連接配接和無連接配接以及之後的Keep-Alive都是指TCP連接配接
  3. 有狀态和無狀态可以指TCP也可以指HTTP
  4. TCP一直有狀态,HTTP一直無狀态,但是應用為了有狀态,就給HTTP加了cookie和session機制,讓使用http的應用也能有狀态,但http還是無狀态

開始TCP是有連接配接,後來TCP無連接配接,再後來也就是現在TCP是Keep-Alive,有點像有連接配接

參考:https://www.cnblogs.com/bellkosmos/p/5237146.html

對Http協定無狀态的了解

Http是一個無狀态協定,同一個會話的連續兩個請求互相不了解,他們由最新執行個體化的環境進行解析,除了應用本身可能已經存儲在全局對象中的所有資訊外,該環境不儲存與會話有關的任何資訊。

自己的了解,在asp.net裡:每次送出伺服器的頁面沒有任何關系,每次記錄在頁面的資訊下次送出是記不住的,(除了應用本身可能已經存儲在全局對象中的所有資訊外)在.net裡實際就是ViewState,ViewState是asp.net中儲存頁面資訊的基本機關,應用時就是儲存在控件隐藏域等中的資料

協定的狀态是指下一次傳輸可以“記住”這次傳輸資訊的能力.

http是不會為了下一次連接配接而維護這次連接配接所傳輸的資訊的.

無狀态是指,當浏覽器發送請求給伺服器的時候,伺服器響應,但是同一個浏覽器再發送請求給伺服器的時候,他會響應,但是他不知道你就是剛才那個浏覽器,簡單地說,就是伺服器不會去記得你,是以是無狀态協定。

而DNS是有狀态協定 。

HTTP是一個屬于應用層的面向對象的協定,HTTP協定一共有五大特點,1、支援客戶/伺服器模式;2、簡單快速;3、靈活;4、無連接配接;5、無狀态;“無狀态”是HTTP協定的主要特點之一,以下為“無狀态”的解釋。 無狀态:是指

協定對于事務處理沒有記憶能力。缺少狀态意味着如果後續處理需要前面的資訊,則它必須重傳,這樣可能導緻每次連接配接傳送的資料量增大。另一方面,在伺服器不需要先前資訊時它的應答就較快。

HTTP是Hyper Text Transfer Protocol的縮寫,顧名思義,這個協定支援着超文本的傳輸。那麼什麼是超文本呢?說白了就是使用HTML編寫的頁面。通常,我們使用用戶端浏覽器通路伺服器的資源,最常見的URL也是以html為字尾的檔案。是以,我們可以說超文本是網絡上最主要的資源。

既然HTTP協定的目的在于支援超文本的傳輸,更加廣義一些就是支援資源的傳輸,那麼在用戶端浏覽器向HTTP伺服器發送請求,繼而HTTP伺服器将相應的資源發回給用戶端這樣一個過程中,無論對于用戶端還是伺服器,都沒有必要記錄這個過程,因為每一次請求和響應都是相對獨立的,就好像你在自動售貨機前投下硬币購買商品一樣,誰都不會也不需要記住這樣一個交易過程。一般而言,一個URL對應着唯一的超文本,而HTTP伺服器也絕對公平公正,不管你是Michael,還是Jordon,它都會根據接收到的URL請求傳回相同的超文本。正是因為這樣的唯一性,使得記錄使用者的行為狀态變得毫無意義,是以,HTTP協定被設計為無狀态的連接配接協定符合它本身的需求。

然而,随着時間的推移,人們發現靜态的HTML着實無聊而乏味,增加動态生成的内容才會令Web應用程式變得更加有用。于是乎,HTML的文法在不斷膨脹,其中最重要的是增加了表單(Form);用戶端也增加了諸如腳本處理、DOM處理等功能;對于伺服器,則相應的出現了CGI(Common Gateway Interface)以處理包含表單送出在内的動态請求。在這種用戶端與伺服器進行動态互動的Web應用程式出現之後,HTTP無狀态的特性嚴重阻礙了這些應用程式的實作,畢竟互動是需要承前啟後的,簡單的購物車程式也要知道使用者到底在之前選擇了什麼商品。于是,兩種用于保持HTTP連接配接狀态的技術就應運而生了,一個是Cookie,而另一個則是Session。

Cookie是通過用戶端保持狀态的解決方案。從定義上來說,Cookie就是由伺服器發給用戶端的特殊資訊,而這些資訊以文本檔案的方式存放在用戶端,然後用戶端每次向伺服器發送請求的時候都會帶上這些特殊的資訊。讓我們說得更具體一些:當使用者使用浏覽器通路一個支援Cookie的網站的時候,使用者會提供包括使用者名在内的個人資訊并且送出至伺服器;接着,伺服器在向用戶端回傳相應的超文本的同時也會發回這些個人資訊,當然這些資訊并不是存放在HTTP響應體(Response Body)中的,而是存放于HTTP響應頭(Response Header);當用戶端浏覽器接收到來自伺服器的響應之後,浏覽器會将這些資訊存放在一個統一的位置,對于Windows作業系統而言,我們可以從:[系統盤]:\Documents and Settings\[使用者名]\Cookies目錄中找到存儲的Cookie;自此,用戶端再向伺服器發送請求的時候,都會把相應的Cookie再次發回至伺服器。而這次,Cookie資訊則存放在HTTP請求頭(Request Header)了。

有了Cookie這樣的技術實作,伺服器在接收到來自用戶端浏覽器的請求之後,就能夠通過分析存放于請求頭的Cookie得到用戶端特有的資訊,進而動态生成與該用戶端相對應的内容。通常,我們可以從很多網站的登入界面中看到“請記住我”這樣的選項,如果你勾選了它之後再登入,那麼在下一次通路該網站的時候就不需要進行重複而繁瑣的登入動作了,而這個功能就是通過Cookie實作的。

與Cookie相對的一個解決方案是Session,它是通過伺服器來保持狀态的。由于Session這個詞彙包含的語義很多,是以需要在這裡明确一下Session的含義。首先,我們通常都會把Session翻譯成會話,是以我們可以把用戶端浏覽器與伺服器之間一系列互動的動作稱為一個Session。從這個語義出發,我們會提到Session持續的時間,會提到在Session過程中進行了什麼操作等等;其次,Session指的是伺服器端為用戶端所開辟的存儲空間,在其中儲存的資訊就是用于保持狀态。從這個語義出發,我們則會提到往Session中存放什麼内容,如何根據鍵值從Session中擷取比對的内容等。

要使用Session,第一步當然是建立Session了。那麼Session在何時建立呢?當然還是在伺服器端程式運作的過程中建立的,不同語言實作的應用程式有不同建立Session的方法,而在Java中是通過調用HttpServletRequest的getSession方法(使用true作為參數)建立的。在建立了Session的同時,伺服器會為該Session生成唯一的Session id,而這個Session id在随後的請求中會被用來重新獲得已經建立的Session;在Session被建立之後,就可以調用Session相關的方法往Session中增加内容了,而這些内容隻會儲存在伺服器中,發到用戶端的隻有Session id;當用戶端再次發送請求的時候,會将這個Session id帶上,伺服器接受到請求之後就會依據Session id找到相應的Session,進而再次使用之。正式這樣一個過程,使用者的狀态也就得以保持了。有關Session的内容還比較多,在以後的Post中,我還将繼續講述。

綜上所述,HTTP本身是一個無狀态的連接配接協定,為了支援用戶端與伺服器之間的互動,我們就需要通過不同的技術為互動存儲狀态,而這些不同的技術就是Cookie和Session了

參考:https://www.cnblogs.com/le-joke/p/5340201.html