當設計、測試或發布一個新的Web API時,你是在一個原有的復雜系統上構建新的系統。那么至少,你也要建立在HTTP上,而HTTP則是基於TCP/IP創建的、TCP/IP建立在一系列的管道上。當然,你也需要考慮Web服務器、應用程序框架或者是API框架。
API從設計到測試以至最終的發布需要經歷一個漫長的過程,本文將主要探討Web API從設計到最終發布,開發者可能忽略或者應該注意的東西。
HTTP篇
HTTP 1.1規范RFC2616是一個非常大的文檔,下面我們節選了一些可能會對API產生影響的內容分享給大家:
1.Idempotent方法:GET、HEAD、PUT、DELETE、OPTIONS以及TRACE都屬於idempotent操作;也就是說,“the side-effects of N > 0 identical requests is the same as for a single request.” (RFC2616 §9.1.2)
2.驗證:用戶訪問API需要進行識別和驗證,HTTP所提供的Authorization頭文件就是出於此目的(RFC2616 §14.8)。RFC2617則指定了具體的驗證計划,包括了最常見的HTTP基本驗證。
3.201 Created:使用“201 Created”響應代碼表示請求成功,並且創建了一個新資源。201響應可以包含本地頭文件中的新資源URI。(RFC2616 §10.2.2)
4.202 Accepted:使用“202 Accepted”響應代碼表示該請求是有效的,將會被處理,但還未完成。一般情況下是用在服務器后台隊列可能出現的地方。(RFC2616 §10.2.3)
5.4XX和5XX狀態代碼:4XX狀態代碼與5XX狀態代碼有一個非常重要的區別:4XX代碼旨在表明客戶端錯誤,而5XX則是表明服務端錯誤。(RFC2616 §6.1.1)
6.410 Gone:“410 Gone”響應代碼是一個很少使用的響應式代碼,其主要是通知客戶端資源出現在URL中,但實際上並沒有。這個用在API里可以指明被刪除、存檔或過期的項目。(RFC2616 §10.4.11)
7.Expect::100-continue:如果API客戶端打算發送一個大型的實體請求,像POST、PUT或PATCH,它可以發送“Expect: 100-continue”到HTTP頭文件里,在發送實體之前等待“100 continue”響應。這就允許API在返回錯誤響應信息之前,可以驗證那些合理的請求(例如401或者403)。使用它可以提高API的響應能力以及在某些情景下減少寬帶。(RFC2616 §8.2.3)
8.保持連接暢通:與API服務器保持連接,對於多API請求是個非常大的性能提升。如果配置正確,每個Web服務器應該支持keep-alive連接。
9.HTTP壓縮:HTTP壓縮可以同時用於響應體(Accept-Encoding: gzip)和請求體(Content-Encoding: gzip),用來提升HTTP API的網絡性能。
10.HTTP緩存:在API響應時提供一個Cache-Control頭文件。(RFC2616 §14.9)
11.緩存驗證:如果你有緩存API,那么在響應時,你應該提供Last-Modified或Etag頭文件,然后支持IF-Modified-Since或者If-None-Match請求頭文件用於有條件的請求。這將允許客戶端檢查它們的緩存副本是否仍然有效,並且當沒有請求時,阻止一個完整的資源下載。如果實現得當,那么條件請求要比普通請求更有效。(RFC2616 §13.3)
12.條件修改:ETag頭文件也可以用於條件修改資源。(RFC2616 §14.24)
13.絕對重定向:這是一個鮮為人知的HTTP/1.1要求,重定向(如。201、301、302、303、307響應代碼)應該包含一個絕對URI本地響應頭文件。許多客戶端在本地支持相對URI,但是如果你想讓API兼容更多客戶端,你應該在重定向時使用絕對URI。(RFC2616 §14.30)
14.鏈接響應頭文件:在RESTful API中,經常需要提供轉向其他資源的鏈接,甚至響應的內容類型無法提供一種自然方式鏈接(例如,PDF或圖像)。RFC5988在響應頭文件中指定了一個鏈接提供方法。
15.規范URL:對於多資源URL,RFC6596定義了統一的方法來規范網址鏈接。
16.塊傳輸編碼:如果響應內容太大,傳輸編碼:分塊(Chunked)是一種很好的流響應到客戶端方式,它將會減少服務器和中間服務器的內存使用需求(尤其是對實現HTTP壓縮),並且提供更快的首字節響應。
17.塊傳輸編碼里的錯誤處理:在實現塊傳輸編碼之前,弄清如何處理發生在中間請求時產生的錯誤是非常重要的。一旦對響應進行流處理,就無法改變HTTP的狀態代碼。
18. X-HTTP-Method-Override:有些HTTP客戶端不支持任何GET和POST,但你可以通過POST開通其他HTTP方法,使用約定成俗的標准X-HTTP-Method-Overrider頭文件去定義“真正”的HTTP方法。
19.URL長度:如果API支持復雜或任意的過濾項作為GET參數,那么記住,無論是客戶端還是服務器端都可能會因為超過2000字節的URL長度帶來兼容性問題。
API設計篇
20.無狀態:沒有人希望API能夠存儲狀態,即使是在你的應用程序服務器端。保持應用程序服務器狀態自由,可以做到很輕易和很輕松地擴展。
21.內容協商:讓你的資源支持多種表現方式,你可以使用內容協商(content negotiation,例如Accept頭文件),或者使用不同的URL(例如……?format=json),或者可以讓你的內容協商重定向到具體的格式。
22.URI模板:URI模板是一個定義良好的機制,用來提供URI組合能力到客戶端,或者定義URL訪問終端用戶模式。
23.Design for Intent:不要僅通過API來暴露內部業務對象,設計API語義意味着要與用戶案例相匹配。更好地介紹,你可以閱讀Darrel Miller寫的API Craft。
24.版本:理論上講,一個設計良好的API是無需創建兼容的。而對於實用主義者,它們會把版本放入到API的URL中(例如:a/v1/path),所以,除非是處在一個安全的網絡狀態下,否則API可能不會按照預期那樣工作。
25.授權:記住,當設計API時,並不是所有的用戶都可以訪問里面的任何對象。
26.批量操作:發送較少的請求來獲取或修改更多的數據,最好的方法就是在你的API里使用批量操作。
27.標記頁數:API中使用分頁服務主要有兩大目的:一個是減少不必要的數據傳送到客戶端;一個是減少應用服務器端不必要的操作。
28.統一的字符編碼:在設計和測試API時,Web服務需要支持更多的英文字符。如果你在URL中把Unicode字節作為自然鍵使用,它將會非常有趣(例如:/users/jimbob/ becomes /users/싸이/)。
29.錯誤日志:在設計API時,創建錯誤日志也是非常重要的。實踐時最好創建兩種日志記錄,一個是服務器端,一個是客戶端。
內容篇
30.內容類型:關於內容類型(Content Type)可以寫整本書,就個人而言,我比較喜歡重用他人開發的內容類型,像Atom、Collection+JSON、JSON HAL或者XHTML。定義一套屬於自己的內容類型會比你期望的更好。
31.HATEOAS:超媒體作為應用程序狀態引擎是一個REST約束,簡單點說就是你的內容應該通知客戶端下面要做的事情,可以通過鏈接或表單來通知。
32.日期/時間:當你在API里提供日期/時間值時,應該使用一種格式,包括時區信息。RFC3339是ISO8601的一個子集,是最簡單的日期時間格式。
安全篇
33.SSL:無論你的API是否支持HTTP或HTTPS,你都應該考慮HTTPS這種訪問方式,它的增長趨勢日益明顯。
34.跨站請求偽造(CSRF):如果使用API的交互式用戶與普通用戶都使用相同的驗證,那么你的API很有可能會遭受CSRF攻擊。
35.Throttling:如果一個API用戶的請求數超過了規定,那么你應該提供一個帶Retry-After header的503響應。
36.婉轉的拒絕服務:Throttling可以阻止你用最簡單的方式進行攻擊,但這里還有其他更機智的攻擊方式。例如Slowloris、Billion laughs、ReDoS,它們都不會占用太多資源,但是它們可以讓你的API在瞬間耗盡所有資源。
客戶端
無論你是否給用戶提供測試代碼或者是SDK開發包,都應該給他們提供一個客戶端,並且遵循下面這幾個步驟:
37.保持連接暢通:一些HTTP客戶端需要做一些額外的工作來保持連接持久,持久的連接對感知API性能有着非常重要的影響。
38.授權之前的401:HTTP的另一個怪癖是,它們會在解決一個授權問題之前發出“401 Unauthorized”響應。這樣就會延長API的請求時間。
39.Expect: 100-continue:至少有一個API客戶端默認使用“Expect: 100-continue”,如果它沒有接受“100 Continue”響應,在3秒的超時后會繼續發送請求。如果API不支持“100 Continue”,或許會產生另一個性能缺陷,導致客戶端禁用。
其它
40.文檔:編寫API文檔是令人厭煩的,但是手寫的API文檔通常是最好的。編寫時一定要包含這些內容:一些可運行的代碼或者curl命令行,方便查閱。你也可以參考一些文檔工具,例如:apiary.io、Mashery I/O Docs、Swagger。
41.設計與客戶:不要在真空中設計API,要與客戶打交道或者一起來設計API,參考用戶用例。
42.反饋:在設計API時,應提供一個通道供用戶進行反饋,
43.自動化測試:API測試是最簡單的事情。它最好是自動化的,畢竟,需要好好利用它。
上面提供的這份列表有趣嗎?對你是否有幫助呢?歡迎與我們一起討論。