有狀態與無狀態協定(stateful vs. stateless protocols)
想像兩種店員。一位有狀態的店員記得你先前的造訪:你走過去說「老樣子,這次加薯條」,他就知道「老樣子」是什麼。一位無狀態的店員在客人之間徹底失憶:每一次,你都得從頭把整份訂單講清楚,因為他對你毫無記憶。這正是有狀態協定與無狀態協定之間的差別——伺服器是否跨越多則訊息保有對某個用戶端的記憶。
在有狀態協定中,伺服器為每段進行中的對話維護狀態——它記得你在一個序列中走到哪、你已經做了什麼、你處於什麼模式。FTP 是有狀態的:你「切換目錄」之後,後續命令都相對於那個目錄來解讀,所以伺服器必須記住它。在無狀態協定中,每則請求都完全自成一體,伺服器在請求之間不保留任何記憶;請求必須攜帶伺服器動作所需的一切。核心的 HTTP 是無狀態的:伺服器並不會自行記得你上一則請求讓你登入了。任何狀態(你的登入、你的購物車)都必須每次重新提供,這正是 Cookie 與權杖存在的原因——在每則請求上把那份脈絡帶回來。
兩種選擇沒有誰「比較好」;它們各有不同的取捨。無狀態協定擴展得極漂亮:正因為伺服器什麼都不記得,一群伺服器中的任何一台都能處理任何請求,請求可以自由地做負載平衡,而一台崩潰的伺服器也不會丟失任何會話記憶。這份簡單與穩健,正是網頁在核心上採無狀態的一大原因。有狀態協定對一段冗長、有序的互動可以更有效率、更具表達力(你只設定一次脈絡然後重複利用),但它把用戶端綁在單一台伺服器上,使崩潰與擴展更難,因為那台伺服器的記憶如今珍貴且不可取代。現代系統設計很大一部分,就是在決定哪份狀態該放在哪裡。
有狀態的 FTP:「CD photos」接著「GET sunset.jpg」——伺服器必須記得你正位在 photos 資料夾裡。無狀態的 HTTP:每則請求都指明完整路徑,GET /photos/sunset.jpg,所以伺服器不需要對前一則請求的記憶;機房裡任何一台伺服器都能一模一樣地回答它。
有狀態=伺服器跨請求記憶;無狀態=每則請求自成一體、自帶脈絡。
無狀態並不代表這個應用程式沒有狀態——你的購物車顯然會留存。它的意思是這個協定在請求之間不在伺服器上保留狀態;狀態被推到別處(一個 Cookie、一個權杖、一個以 ID 為索引的資料庫)。