有人提了一個(gè)問題:一定要RESTful嗎?
寫在前面的話
這個(gè)問題看起來(lái)就顯得有些萌,或者說類似的問題都有些不靠譜,世上哪有那么多一定的事情,做開發(fā)都不一定做多久呢,所以說如果你有這個(gè)疑問的話是真真有點(diǎn)兒不著調(diào),不過可能也就是隨口一問吧,沒有深究的必要。既然有人問這個(gè),那么就再用一篇文章談?wù)凴ESTful吧,既然談,就不能只是談其優(yōu)點(diǎn),也不能一味的吹捧,也講一下自己的一些理解和不足的地方。
規(guī)范、易讀、簡(jiǎn)潔?
Spring+SpringMVC+MyBatis+easyUI整合進(jìn)階篇(一)設(shè)計(jì)一套好的RESTful API
Spring+SpringMVC+MyBatis+easyUI整合進(jìn)階篇(三)使用ajax方法實(shí)現(xiàn)form表單的提交
Spring+SpringMVC+MyBatis+easyUI整合進(jìn)階篇(四)RESTful API實(shí)戰(zhàn)筆記(前端代碼修改)
前文中已經(jīng)談了RESTful不少的優(yōu)點(diǎn),也做了代碼更新,首先,REST強(qiáng)調(diào)HTTP應(yīng)當(dāng)以資源為中心,并且規(guī)范了資源URI的風(fēng)格;規(guī)范了HTTP請(qǐng)求動(dòng)作(PUT,POST等)的使用,具有對(duì)應(yīng)的語(yǔ)義;遵循REST規(guī)范的Web應(yīng)用將會(huì)獲得下面好處:URL具有很強(qiáng)可讀性的,具有自描述性;資源描述與視圖的松耦合;可提供OpenAPI,便于第三方系統(tǒng)集成,提高互操作性;如果提供無(wú)狀態(tài)的服務(wù)接口,可提高應(yīng)用的水平擴(kuò)展性;
總結(jié)下來(lái):規(guī)范、易讀,但是這兩個(gè)優(yōu)點(diǎn)也帶來(lái)一些不盡如人意的"反效果":
- 因?yàn)镽ESTful規(guī)范較為明確且有一定的"強(qiáng)制性",這種限制反而導(dǎo)致設(shè)計(jì)uri變得復(fù)雜了,尤其是復(fù)雜的關(guān)系,操作,資源集合,硬性套用rest原則設(shè)計(jì)非常困難。
- 對(duì)于RESTful的爭(zhēng)論無(wú)處不在,都在討論正確性和規(guī)范性,即使和同事之間也會(huì)有類似的爭(zhēng)執(zhí),當(dāng)我們?cè)跔?zhēng)論Restful風(fēng)格到底如何設(shè)計(jì)才是正宗時(shí),發(fā)現(xiàn)心中的困惑不僅沒有降低,反而增加了。
- RESTful思想及其所倡導(dǎo)的規(guī)范很正確,但是使用者的行為太刻意了反而導(dǎo)致這個(gè)東西變了味道,爭(zhēng)來(lái)爭(zhēng)去就是為了證明自己的理解和使用最"正宗"。
RESTful中的模棱兩可
前一個(gè)段落可能有些過于概念化了,還是舉一些具體的例子吧。
案例一
其實(shí),RESTful中也存在著許多的模棱兩可,也有很多不是那么讓開發(fā)人員舒服的地方,有人會(huì)去糾結(jié)查詢、增加、修改、刪除(對(duì)應(yīng)的方法就是get、post、put、delete),個(gè)人認(rèn)為這并不完全正確,因?yàn)檫@個(gè)想法把開發(fā)工作中的業(yè)務(wù)場(chǎng)景過于簡(jiǎn)單化和模板化了,我們開發(fā)的功能就只實(shí)現(xiàn)這四類操作嗎、如果遇到一些不能完全對(duì)應(yīng)上這四種方式的業(yè)務(wù)該怎么辦呢?
- 發(fā)短信、支付、用戶登錄認(rèn)證,該用get、post、put、delete中的哪一個(gè)HTTP動(dòng)詞?
- login和logout應(yīng)該怎么REST化?
- 驗(yàn)證碼發(fā)送該如何定義uri?
類似的問題還有很多,感覺很多朋友會(huì)遇到類似的問題,心里面也有一些不確定該如何去做,其實(shí)在理解了REST后,這些并不是什么無(wú)解的難題,只是思維方式要轉(zhuǎn)換一下: login和logout其實(shí)只是對(duì)session資源或者cookie資源的創(chuàng)建和刪除;業(yè)務(wù)的uri如何選擇HTTP動(dòng)詞也要靈活變通,規(guī)范是死的,人是活的,按照自己的理解去做,如果后期發(fā)現(xiàn)錯(cuò)誤即使糾正就好了。不過,雖然API如何編寫是開發(fā)者的自由,但如果一個(gè)API在url里放一堆動(dòng)詞、資源設(shè)計(jì)混亂、各種亂用HTTP Method和Status Code,就太不像話了,規(guī)范嘛還是要遵守的,說了這么多理解上的偏差,其實(shí)代碼質(zhì)量才是最重要的,有些手段其實(shí)只是讓代碼看起來(lái)比較優(yōu)雅的手段而已。
案例二
以上是針對(duì)于RESTful理解和設(shè)計(jì)上的一個(gè)例子,具體工作中還有其他的例子嗎?也是很多的,比如,比較棘手的一個(gè)問題:跨域資源共享 CORS。
在實(shí)際進(jìn)行跨域請(qǐng)求時(shí),經(jīng)常會(huì)遇到類似 No 'Access-Control-Allow-Origin' header is present on the requested resource.這樣的報(bào)錯(cuò):
這個(gè)問題并不是因?yàn)镽ESTful引起的,也不能通過修改RESTful的規(guī)范去解決,舉這個(gè)例子的原因是因?yàn)樵诮涌诘腞ESRful化時(shí)也遇到過這個(gè)問題,解決辦法就不在本文中列舉了,有興趣的朋友可以看一下跨域資源共享 CORS 詳解這篇文章,以后有時(shí)間會(huì)把解決方案整理出來(lái)的。
一些需要重視的安全性問題
當(dāng)然,不止是以上的兩個(gè)問題,前一個(gè)段落主要是講述了一下理解和具體使用上的問題,這一段講一下可能引發(fā)的安全性問題。
遺漏了對(duì)資源從屬關(guān)系的檢查
一個(gè)典型的RESTful的URL會(huì)用資源名加上資源的id編號(hào)來(lái)標(biāo)識(shí)其唯一性,就像這樣:/users/{userid},例如:/users/100
一般而言用戶只能查看自己的用戶信息,而不允許查看其它用戶的信息。在這種情況下,攻擊者很可能會(huì)嘗試把這個(gè)URL里面的USER ID從100修改為其他數(shù)值,以期望應(yīng)用返回指定用戶的信息。不過由于這個(gè)安全風(fēng)險(xiǎn)太顯而易見,絕大多數(shù)應(yīng)用都會(huì)對(duì)當(dāng)前請(qǐng)求者的身份進(jìn)行校驗(yàn),看其是否是編號(hào)為100的用戶,校驗(yàn)成功才返回URL中指定的用戶信息,否則會(huì)拒絕當(dāng)前請(qǐng)求。
不經(jīng)意間泄露的業(yè)務(wù)信息
以查看用戶信息的RESTful URL為例:/users/100。由于用戶ID是一個(gè)按序遞增的數(shù)字,因此攻擊者既可以通過ID知道目前應(yīng)用中的用戶規(guī)模,也可以分別在月初和月末的時(shí)候注冊(cè)一個(gè)用戶,并對(duì)比兩個(gè)用戶的ID即可知道當(dāng)前這個(gè)月有多少新增用戶。同理,如果訂單號(hào)也是按序自增的數(shù)字,攻擊者可以了解到一定時(shí)間范圍內(nèi)的訂單量。
這類ID并不會(huì)給應(yīng)用造成任何技術(shù)上的威脅,只是通過ID泄露出來(lái)的信息對(duì)于你的業(yè)務(wù)而言可能非常敏感。解決辦法是不使用按序遞增的數(shù)字作為ID,而是使用具有隨機(jī)性、唯一性、不可預(yù)測(cè)性的值作為ID,最常見的做法就是使用UUID。
參考RESTful架構(gòu)風(fēng)格下的4大常見安全問題
選擇適合自己的方式
Spring+SpringMVC+MyBatis+easyUI整合進(jìn)階篇(五)記錄一下從懵懂到理解RESTful的過程
前一篇博客中也提到了很多其他的方式,比如傳統(tǒng)的MVC開放形式,比如webservice,比如rpc調(diào)用,RESTful也只是其中的一種而已,這些選項(xiàng)中并沒有高下之分,無(wú)非是多種約定俗成的標(biāo)準(zhǔn),傳統(tǒng)MVC開發(fā)著舒服就按MVC模式來(lái)開發(fā),習(xí)慣用RPC就用RPC,能理解和接受REST就用REST。
前幾篇文章中描述了RESTful那么多的優(yōu)點(diǎn),現(xiàn)在又說大可不必使用,前文又提到RESTful是好的設(shè)計(jì)實(shí)踐,現(xiàn)在又是另外一種說法,不是自相矛盾嗎?
這是我的文章,我肯定要按照我的一些想法寫啊,可能有不對(duì)的地方,前文中提到的是好的設(shè)計(jì)實(shí)踐也是我的個(gè)人想法和理解,這篇的開頭就說了,不能只談優(yōu)點(diǎn),所以又列舉了一些不足吧,我寫文章不是挑口水,很沒必要,選擇適合自己的技術(shù)和規(guī)范就好。
套用網(wǎng)絡(luò)上比較流行的一句話:聽了很多道理卻依然過不好一生。
作為一名開發(fā)人員,自己動(dòng)手去實(shí)踐才是硬道理,別人說什么都不要全盤接受,你要想想適不適合你,適不適合你目前做的項(xiàng)目,鞋合不合適只有腳知道,just do it!
結(jié)語(yǔ)
優(yōu)點(diǎn)也好,缺點(diǎn)也罷,雖然看似也總結(jié)了不少,但都是個(gè)人見解,肯定還有一些遺漏的地方?jīng)]有講清楚,還請(qǐng)見諒。
回答文章一開始的問題,是不是一定要用呢?是不是一定要遵循其規(guī)則呢?如果不能解決你所面對(duì)的問題,不能提高和提升代碼質(zhì)量、提升工作效率,其實(shí)大可不必如此介懷,不用就是了。
首發(fā)于我的個(gè)人博客,編輯于2017年10月13日晚11:37分。