關於Restful 和JSON-RPC的 一點理解

  • REST要求要將接口以資源的形式呈現。但實際上,很多時候都不太可能將一些業務邏輯看作資源。即使強制這麼幹了,也會非常非常彆扭。登錄就是登錄,而不是“創建一個session”;播放音樂就是播放,而不是“創建一個播放狀態“。
  • REST只提供了增刪改查的基本語義,其他的語義基本上不管。比如批量添加,批量刪除,修改一個資源的一部分字段。區分“物理刪除”和“標記刪除”等等。複雜的查詢更加不顯示,對於像篩選這類的場景,REST明顯就是個渣。這裏要表揚一下GraphQL(但GraphQL有其他的問題,在此不展開)
  • REST建議用HTTP的status
    code做錯誤碼,以便於“統一”,實際上這非常難統一。各種業務的含義五花八門,抽象層次高低不齊,根本就無法滿足需要。比如一個404到底是代表這個接口找不到,還是代表一個資源找不到。400表達請求有問題,但是我想提示用戶“你登錄手機號輸入的格式不對“,還是“你登錄手機號已經被佔用了“。既然201表示“created”,爲啥deleted和updated沒有對應的status
    code,只能用200或者204(no
    content)?錯誤處理是web系統裏最麻煩的,最需要細心細緻的地方。REST風格在這裏只能添亂。
  • web請求參數可能散佈在url
    path、querystring、body、header。服務器端處理對此完全沒有什麼章法。客戶端和服務器端的研發之間還是要做約定。
  • 在url path上的變量會對很多其他的工作帶來不良影響。

比如監控,本來url可以作爲一個接口的key統計次數/延遲,結果url裏出了個變量,所以自動收集nginx的access
log,自動做監控項目增加就沒法弄了。再比如,想對接口做流量控制的計數,本來url可以做key,因爲有變量,就得多費點事纔行。

  • 現實中接口要處理的真正的問題,REST基本上也沒怎麼管。比如認證、授權、流控、數據緩存(http的etag還起了點作用)、超時控制、數據壓縮……
  • REST有很多好的工具可以便利的生成對應的代碼和文檔,也容易形成規範。但問題是REST在實際的項目中並沒有解決很多問題,也在很多時候不合用,因此產生的代碼和文檔也就沒什麼用,必須經過二次加工才能真的用起來。因此可以基於REST+你的業務場景定義一個你自己的規範。

REST的本意是基於一個架構的假設(資源化),定義了一組風格,並基於這個風格形成約定、工具和支持。思路不錯。但是因爲他的架構假設就是有問題的,因此後續一系列東西都建立在了一個不穩固的基礎之上。
同時,REST並沒有解決太多的實際問題。是,的確,有些時候,用REST完成CRUD已經能完成任務了。此時,用REST沒有什麼不好的。
但是,現實當中,真正的業務領域一般都會比資源的CRUD複雜的多。
這時REST“基本上沒解決太多實際問題”的缺點就會體現出來。
我所見到的大多數情況,是會形成一種REST-like形式的接口,像REST卻又不限於REST。爲了REST,我看到了太多的人在爭執到底是POST還是PUT,到底用querystring還是body,到底用200還是201,到底一個單詞應該用單數還是複數,到底一個請求參數應該放在url path的中間一段還是最後一段…… 真正要做的事情本身反而沒人關心。
現實當中接口的開發的方式你可以總是從REST開始,如果你要開發的東西能被自然而然的想成是一個資源。然後通過相關的工具自動生成一些代碼,把這個原型和你的合作者討論一下。
這是我能想到的REST能做的一件很好的事情——快速實驗。
然後如果你想認真的往下做,就可以徹底忘記REST這件事。開始自己定義業務接口,儘量不要在url里加變量。儘量只用GET和POST,減少一些溝通上的混亂。
對於每個接口,好好定義可能發生的業務錯誤,並與PM一起協商怎麼處理這些錯誤。認真的考慮認證、授權、流控等機制,當你開發的是和錢相關的業務尤其要留意。
最後,本文並不是說“絕對不要用REST”,而是:如果你在實際工作中用REST有了困惑,不知道某個情況下REST此時的最佳實踐是什麼時,不要追求“真正的REST會怎麼做”,不要被REST限制住。

=======
restful首先是要求必須把所有的應用定義成爲“resource”,然後只能針對資源做有限的四種操作。
這是對API一個非常糟糕的抽象,有太多現實中需要的API,無法順當的融入到restful所定義的規範中。
比方說,user login / resetpassword等等。restful的信徒,他們會說可以根據這個那個規範,把login / password等也納入爲某種資源,然後進行增刪改查。這在我看來,純粹是在解決一些原本不存在,根本不需要解決的問題,純浪費。所有的接口,服務器端原本就存在有相應的函數,它們本來就有自身的命名空間,接受的參數、返回值、異常等等。採用輕便的方式暴露出來即可。
無需把一堆函數重新歸納到“資源”,再削減腦袋把所有的操作都映射爲“增刪改查”。對應到web上,rpc的成熟方案非常多,有古老的soap,也有輕量的json rpc。JSON rpc基本上僅是要求所有的請求必須有msg id,有函數名,然後可定義參數,並且區分返回值與異常;也可定義『命名空間』來對函數模塊做劃分。這與大多數語言的模塊、函數定義相符,使用起來是非常便利的。很多json rpc是供web前端ajax調用,若前端調用抽象得當,調用遠程API,實際上與調用本地函數無甚區別。實際上,json rpc也未必需要跟http綁定,即便是在web上,它也可以走web socket,這樣子,前端可以使用同一web socket管道批量發送請求,而服務器端亂序返回結果時,前端也可以根據msg id做準確的回調。websocket,批量調用,亂序返回,這些都可以顯著提高API的輸出吞吐,這些是在json rpc的設計考量內。調用更方便,性能也更好,兩全其美是完全可能的。想當然的爲了“快”,爲了“簡單”就必須犧牲別的,這是嚴重的思維誤區。有些方案,純粹就是糟糕的方案。restful API僅適用與業務非常簡單的場景,比方說,就是爲了提供少量數據表單的增刪改查。而這種場景實在是太過簡單,實際中幾乎找不到。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章