對於REST中無狀態(stateless)的一點認識(轉)

  在請求中傳遞SessionID被廣泛認爲是unRESTful的,而將用戶的credentials包含在每一個請求裏又是一種很是RESTful的作法。這樣一個問題常常會形成困擾。本文就REST的一些概念進行了探討,解釋了REST架構中的狀態,無狀態(stateless),以及兩種狀態的區別後端

  

  今天早上在Yahoo的郵件列表裏看到一篇很有意思的討論,標題爲RESTful vs. unRESTful: Session IDs and Authentication(51CTO編者注:意爲REST對非REST,Session ID與驗證)。文中讓發起討論的朋友大惑不解的是這樣一個問題:爲何在請求中傳遞SessionID被廣泛認爲是unRESTful的,而將用戶的credentials包含在每一個請求裏又是一種很是RESTful的作法。看了他接下來對於REST架構風格中"statelessness"屬性的理解後,我以爲有必要對這個常常會被人誤解詞彙以及相關概念作一個簡要的整理,但願可以經過這篇隨筆解釋清楚什麼是狀態,爲何要實現無狀態,以及REST風格架構中的兩種狀態的區別,最後我會從個人理解出發來回答做者提出的這個問題。瀏覽器

  首先,一個Web應用程序協議的「狀態」在一般指的是爲兩個相互關聯的用戶交互操做保留的某種公共信息,它們經常被用來存儲工做流或用戶狀態信息等數據。這些信息能夠被指定不一樣的做用域如page,request,session或全局做用域,而存儲他們的責任也一樣能夠由Client端或Server端負責。雖然存儲狀態爲企業軟件開發帶來了諸多便利,可是它也給分佈式系統的其餘方面帶來了許多限制,好比在負載均衡方面,在有狀態的模式下,一個用戶的請求必須被提交到保存有其相關狀態信息的服務器上,不然這些請求可能沒法被理解,這也就意味着在此模式下服務器端沒法對用戶請求進行自由調度。於此相關的另外一個問題是容錯性,假若保有用戶信息的服務器宕機,那麼該用戶最近的全部交互操做將沒法被透明地移送至備用服務器上,除非該服務器時刻與主服務器同步所有用戶的狀態信息。此外,因爲HTTP自己不是一個有狀態的協議,開發人員必須經過模擬實現狀態的鈍化與激活等。因而爲了克服這些不足,無狀態(Statelessness)架構風格屬性受到了普遍關注。安全

  無狀態指的是任意一個Web請求必須徹底與其餘請求隔離,當請求端提出請求時,請求自己包含了相應端爲相應這一請求所需的所有信息。這一約束的出現改善了分佈式系統的可見性、可靠性以及可伸縮性,具體的介紹能夠參考Roy T. Fielding博士的論文,這裏就不哆嗦了。這些從整個系統角度來看無狀態彷佛過於抽象,那麼對於用戶來講,怎麼感受的有狀態與無狀態的差異呢。簡單的方法是瀏覽器的後退按鈕,若是一個網站指望用戶以A->B->C的流程來交互,而在執行至B時回退的話,那麼系統頗有可能不是按照其所指望的方式運行,由於用戶的狀態可能被不可逆地修改了。反過來,搜索引擎(我指的是普通意義上的搜索引擎,而不是根據用戶搜索歷史個性化了的)是一個無狀態架構的範例。任何用戶能夠在瀏覽器地址欄中輸入http://www.google.com/search?q=RESTful&start=100來得到從第一百條開始的關於RESTful的記錄,而且當Google摩洛哥服務器癱瘓時,相關用戶請求會被透明地移送至其餘服務器。服務器

  一切彷佛很明瞭,那麼是什麼致使了那位朋友的誤解呢,答案是RESTful架構對於state的兩個不一樣的解釋: 應用狀態(Application State)和資源狀態(Resource State)。應用狀態指的是與某一特定請求相關的狀態信息,而資源狀態則反映了某一存儲在服務器端資源在某一時刻的特定狀態,該狀態不會由於用戶請求而改變,任何用戶在同一時刻對該資源的請求都會得到這一狀態的表現(Representation)。RESTful架構要求服務器端不保有任何與特定HTTP請求相關的資源,因此應用狀態必須由請求方在請求過程當中提供。那麼再回到那個郵件列表中的問題,爲何傳遞一個session ID是違背REST架構風格而傳遞user credentials卻不是。我想做者的疑惑源於他沒有分清什麼是有狀態和無狀態的架構屬性,而認爲「傳遞某種表示狀態的信息」到服務器即是「有狀態」的表現。其實有狀態和無狀態與請求自己沒有多大關聯,重要的是狀態信息是由請求方仍是響應方負責保存。在Session ID能夠被認爲是一個用來標識某一會話狀態的Key,將其傳遞給服務器端意味着這樣一個請求:「請幫我取出這個狀態信息」,也就是說這個請求假設響應方保有着狀態信息。因爲與某一特定請求相關的狀態屬於應用狀態,而RESTful架構要求任何此類狀態由請求方負責提供,因此傳遞Session ID被認爲是unRESTful的作法。反過來,user credential做爲一種應用狀態,是被指望由請求方提供的,因此在請求中傳遞user credentials(姑且忽略安全性問題)是符合RESTful架構規範的。session

  這篇隨筆或多或少散發着某種純粹主義的味道,但我以爲有些概念是值得玩味的。任何一種架構風格的出現都有其指望的,對現有方案的改進或指望克服的問題。做爲REST來講,它所指望的是組件的可伸縮性,組件的獨立部署,接口統一等特性,而無狀態做爲實現這組需求的一個特性,我的認爲是有必要清楚瞭解並實際開發過程當中落實的。架構

 

  RESTful 架構中須要分離出 OAuth 服務,將全部的應用認證統一管理,後續的每次請求都須要經過受權服務,再轉向到服務器,進行權限管理,這樣,就能夠將應用的驗證狀態分離出來,使得後端分佈式變爲無狀態方式,以後的負載或者其餘的處理,更加簡單,可是,分離出來,架構複雜度提高,維護和開發、測試的成本增長負載均衡

 

原文地址:http://developer.51cto.com/art/200906/129424.htmless

相關文章
相關標籤/搜索