久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

撰寫合格的REST API

 icecity1306 2015-05-21

兩周前因?yàn)楣疽淮尾萌?,好幾個(gè)人的活都被按在了我頭上,這其中的一大部分是一系列REST API,,撰寫者號稱基本完成,,我測試了一下,,發(fā)現(xiàn)盡管從功能的角度來說,這些API實(shí)現(xiàn)了spec的顯式要求,,但是從實(shí)際使用的角度,,欠缺的東西太多(各種各樣的隱式需求)。REST API是一個(gè)系統(tǒng)的backend和frontend(或者3rd party)打交道的通道,,承前啟后,,有很多很多隱式需求,比如調(diào)用接口與RFC保持一致,,API的內(nèi)在和外在的安全性等等,,并非提供幾個(gè)endpoint,返回相應(yīng)的json數(shù)據(jù)那么簡單,。仔細(xì)研究了原作者的代碼,,發(fā)現(xiàn)缺失的東西實(shí)在太多,每個(gè)API基本都在各自為戰(zhàn),,與其修補(bǔ),,不如重寫(并非是程序員相輕的緣故),于是我花了一整周,,重寫了所有的API,。稍稍總結(jié)了些經(jīng)驗(yàn),在這篇文章里講講如何撰寫「合格的」REST API,。

RFC一致性

REST API一般用來將某種資源和允許的對資源的操作暴露給外界,,使調(diào)用者能夠以正確的方式操作資源。這里,,在輸入輸出的處理上,,要符合HTTP/1.1(不久的將來,要符合HTTP/2.0)的RFC,,保證接口的一致性,。這里主要講輸入的method/headers和輸出的status code。

Methods

HTTP協(xié)議提供了很多methods來操作數(shù)據(jù):

  • GET: 獲取某個(gè)資源,,GET操作應(yīng)該是冪等(idempotence)的,,且無副作用。

  • POST: 創(chuàng)建一個(gè)新的資源,。

  • PUT: 替換某個(gè)已有的資源。PUT操作雖然有副作用,,但其應(yīng)該是冪等的,。

  • PATCH(RFC5789): 修改某個(gè)已有的資源。

  • DELETE:刪除某個(gè)資源,。DELETE操作有副作用,,但也是冪等的,。

冪等在HTTP/1.1中定義如下:

Methods can also have the property of "idempotence" in that (aside from error or expiration issues) the side-effects of N > 0 identical requests is the same as for a single request. 如今鮮有人在撰寫REST API時(shí),

簡單說來就是一個(gè)操作符合冪等性,,那么相同的數(shù)據(jù)和參數(shù)下,,執(zhí)行一次或多次產(chǎn)生的效果(副作用)是一樣的。

現(xiàn)在大多的REST framwork對HTTP methods都有正確的支持,,有些舊的framework可能未必對PATCH有支持,,需要注意。如果自己手寫REST API,,一定要注意區(qū)分POST/PUT/PATCH/DELETE的應(yīng)用場景,。

Headers

很多REST API犯的比較大的一個(gè)問題是:不怎么理會request headers。對于REST API,,有一些HTTP headers很重要:

  • Accept:服務(wù)器需要返回什么樣的content,。如果客戶端要求返回"application/xml",服務(wù)器端只能返回"application/json",,那么最好返回status code 406 not acceptable(RFC2616),,當(dāng)然,返回application/json也并不違背RFC的定義,。一個(gè)合格的REST API需要根據(jù)Accept頭來靈活返回合適的數(shù)據(jù),。

  • If-Modified-Since/If-None-Match:如果客戶端提供某個(gè)條件,那么當(dāng)這條件滿足時(shí),,才返回?cái)?shù)據(jù),,否則返回304 not modified。比如客戶端已經(jīng)緩存了某個(gè)數(shù)據(jù),,它只是想看看有沒有新的數(shù)據(jù)時(shí),,會用這兩個(gè)header之一,服務(wù)器如果不理不睬,,依舊做足全套功課,,返回200 ok,那就既不專業(yè),,也不高效了,。

  • If-Match:在對某個(gè)資源做PUT/PATCH/DELETE操作時(shí),服務(wù)器應(yīng)該要求客戶端提供If-Match頭,,只有客戶端提供的Etag與服務(wù)器對應(yīng)資源的Etag一致,,才進(jìn)行操作,否則返回412 precondition failed,。這個(gè)頭非常重要,,下文詳解。

Status Code

很多REST API犯下的另一個(gè)錯(cuò)誤是:返回?cái)?shù)據(jù)時(shí)不遵循RFC定義的status code,而是一律200 ok + error message,。這么做在client + API都是同一公司所為還湊合可用,,但一旦把API暴露給第三方,不但貽笑大方,,還會留下諸多互操作上的隱患,。

以上僅僅是最基本的一些考慮,要做到完全符合RFC,,除了參考RFC本身以外,,erlang社區(qū)的webmachine或者clojure下的liberator都是不錯(cuò)的實(shí)現(xiàn),是目前為數(shù)不多的REST API done right的library/framework,。

 
 

(liberator的decision tree,,沿襲了webmachine的思想,請自行g(shù)oogle其文檔查看大圖)

安全性

前面說過,,REST API承前啟后,,是系統(tǒng)暴露給外界的接口,所以,,其安全性非常重要,。安全并單單不意味著加密解密,而是一致性(integrity),,機(jī)密性(confidentiality)和可用性(availibility),。

請求數(shù)據(jù)驗(yàn)證

我們從數(shù)據(jù)流入REST API的第一步 —— 請求數(shù)據(jù)的驗(yàn)證 —— 來保證安全性。你可以把請求數(shù)據(jù)驗(yàn)證看成一個(gè)巨大的漏斗,,把不必要的訪問統(tǒng)統(tǒng)過濾在第一線:

  • Request headers是否合法:如果出現(xiàn)了某些不該有的頭,,或者某些必須包含的頭沒有出現(xiàn)或者內(nèi)容不合法,根據(jù)其錯(cuò)誤類型一律返回4xx,。比如說你的API需要某個(gè)特殊的私有頭(e.g. X-Request-ID),,那么凡是沒有這個(gè)頭的請求一律拒絕。這可以防止各類漫無目的的webot或crawler的請求,,節(jié)省服務(wù)器的開銷,。

  • Request URI和Request body是否合法:如果請求帶有了不該有的數(shù)據(jù),或者某些必須包含的數(shù)據(jù)沒有出現(xiàn)或內(nèi)容不合法,,一律返回4xx,。比如說,API只允許querystring中含有query,,那么"?sort=desc"這樣的請求需要直接被拒絕,。有不少攻擊會在querystring和request body里做文章,最好的對應(yīng)策略是,,過濾所有含有不該出現(xiàn)的數(shù)據(jù)的請求,。

數(shù)據(jù)完整性驗(yàn)證

REST API往往需要對backend的數(shù)據(jù)進(jìn)行修改,。修改是個(gè)很可怕的操作,我們既要保證正常的服務(wù)請求能夠正確處理,,還需要防止各種潛在的攻擊,如replay,。數(shù)據(jù)完整性驗(yàn)證的底線是:保證要修改的數(shù)據(jù)和服務(wù)器里的數(shù)據(jù)是一致的 —— 這是通過Etag來完成,。

Etag可以認(rèn)為是某個(gè)資源的一個(gè)唯一的版本號。當(dāng)客戶端請求某個(gè)資源時(shí),,該資源的Etag一同被返回,,而當(dāng)客戶端需要修改該資源時(shí),需要通過"If-Match"頭來提供這個(gè)Etag,。服務(wù)器檢查客戶端提供的Etag是否和服務(wù)器同一資源的Etag相同,,如果相同,才進(jìn)行修改,,否則返回412 precondition failed,。

使用Etag可以防止錯(cuò)誤更新。比如A拿到了Resource X的Etag X1,,B也拿到了Resource X的Etag X1,。B對X做了修改,修改后系統(tǒng)生成的新的Etag是X2,。這時(shí)A也想更新X,,由于A持有舊的Etag,服務(wù)器拒絕更新,,直至A重新獲取了X后才能正常更新,。

Etag類似一把鎖,是數(shù)據(jù)完整性的最重要的一道保障,。Etag能把絕大多數(shù)integrity的問題扼殺在搖籃中,,當(dāng)然,race condition還是存在的:如果B的修改還未進(jìn)入數(shù)據(jù)庫,,而A的修改請求正好通過了Etag的驗(yàn)證時(shí),,依然存在一致性問題。這就需要在數(shù)據(jù)庫寫入時(shí)做一致性寫入的前置檢查,。

訪問控制

REST API需要清晰定義哪些操作能夠公開訪問,,哪些操作需要授權(quán)訪問。一般而言,,如果對REST API的安全性要求比較高,,那么,所有的API的所有操作均需得到授權(quán),。

在HTTP協(xié)議之上處理授權(quán)有很多方法,,如HTTP BASIC Auth,,OAuth,HMAC Auth等,,其核心思想都是驗(yàn)證某個(gè)請求是由一個(gè)合法的請求者發(fā)起,。Basic Auth會把用戶的密碼暴露在網(wǎng)絡(luò)之中,并非最安全的解決方案,,OAuth的核心部分與HMAC Auth差不多,,只不過多了很多與token分發(fā)相關(guān)的內(nèi)容。這里我們主要講講HMAC Auth的思想,。

回到Security的三個(gè)屬性:一致性,,機(jī)密性,和可用性,。HMAC Auth保證一致性:請求的數(shù)據(jù)在傳輸過程中未被修改,,因此可以安全地用于驗(yàn)證請求的合法性。

HMAC主要在請求頭中使用兩個(gè)字段:Authorization和Date(或X-Auth-Timestamp),。Authorization字段的內(nèi)容由":"分隔成兩部分,,":"前是access-key,":"后是HTTP請求的HMAC值,。在API授權(quán)的時(shí)候一般會為調(diào)用者生成access-key和access-secret,,前者可以暴露在網(wǎng)絡(luò)中,后者必須安全保存,。當(dāng)客戶端調(diào)用API時(shí),,用自己的access-secret按照要求對request的headers/body計(jì)算HMAC,然后把自己的access-key和HMAC填入Authorization頭中,。服務(wù)器拿到這個(gè)頭,,從數(shù)據(jù)庫(或者緩存)中取出access-key對應(yīng)的secret,按照相同的方式計(jì)算HMAC,,如果其與Authorization header中的一致,,則請求是合法的,且未被修改過的,;否則不合法,。

GET /photos/puppy.jpg HTTP/1.1
Host: johnsmith.s3.amazonaws.com
Date: Mon, 26 Mar 2007 19:37:58 +0000

Authorization: AWS AKIAIOSFODNN7EXAMPLE:frJIUN8DYpKDtOLCwo//yllqDzg=
 
 

(Amazon HMAC圖示)

在做HMAC的時(shí)候,request headers中的request method,,request URI,,Date/X-Auth-Timestamp等header會被計(jì)算在HMAC中。將時(shí)間戳計(jì)算在HMAC中的好處是可以防止replay攻擊,??蛻舳撕头?wù)器之間的UTC時(shí)間正常來說偏差很小,那么,,一個(gè)請求攜帶的時(shí)間戳,,和該請求到達(dá)服務(wù)器時(shí)服務(wù)器的時(shí)間戳,,中間差別太大,超過某個(gè)閾值(比如說120s),,那么可以認(rèn)為是replay,,服務(wù)器主動丟棄該請求。

使用HMAC可以很大程度上防止DOS攻擊 —— 無效的請求在驗(yàn)證HMAC階段就被丟棄,,最大程度保護(hù)服務(wù)器的計(jì)算資源,。

HTTPS

HMAC Auth盡管在保證請求的一致性上非常安全,可以用于鑒別請求是否由合法的請求者發(fā)起,,但請求的數(shù)據(jù)和服務(wù)器返回的響應(yīng)都是明文傳輸,對某些要求比較高的API來說,,安全級別還不夠,。這時(shí)候,需要部署HTTPS,。在其之上再加一層屏障。

其他

做到了接口一致性(符合RFC)和安全性,REST API可以算得上是合格了,。當(dāng)然,,一個(gè)實(shí)現(xiàn)良好的REST API還應(yīng)該有如下功能:

  • rate limiting:訪問限制。

  • metrics:服務(wù)器應(yīng)該收集每個(gè)請求的訪問時(shí)間,,到達(dá)時(shí)間,,處理時(shí)間,latency,,便于了解API的性能和客戶端的訪問分布,,以便更好地優(yōu)化性能和應(yīng)對突發(fā)請求。

  • docs:豐富的接口文檔 - API的調(diào)用者需要詳盡的文檔來正確調(diào)用API,,可以用swagger來實(shí)現(xiàn),。

  • hooks/event propogation:其他系統(tǒng)能夠比較方便地與該API集成。比如說添加了某資源后,,通過kafka或者rabbitMQ向外界暴露某個(gè)消息,,相應(yīng)的subscribers可以進(jìn)行必要的處理。不過要注意的是,,hooks/event propogation可能會破壞REST API的冪等性,,需要小心使用。

各個(gè)社區(qū)里面比較成熟的REST API framework/library:

  • Python: django-rest-framework(django),,eve(flask),。各有千秋??上ython沒有好的類似webmachine的實(shí)現(xiàn),。

  • Erlang/Elixir: webmachine/ewebmachine,。

  • Ruby: webmachine-ruby。

  • Clojure:liberator,。

其它語言接觸不多,,就不介紹了??梢酝ㄟ^訪問該語言在github上相應(yīng)的awesome repo(google awesome XXX,,如awesome python),查看REST API相關(guān)的部分,。

如果您覺得這篇文章不錯(cuò),,請點(diǎn)贊。多謝,!


歡迎訂閱公眾號『程序人生』(搜索微信號 programmer_life),。每篇文章都力求原汁原味,北京時(shí)間中午12點(diǎn)左右,,美西時(shí)間下午8點(diǎn)左右與您相會,。

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多