請求--響應類的API的典型作法是,經過基於HTTP的Web服務器暴露一個/套接口。API定義一些端點,客戶端發送數據的請求到這些端點,Web服務器處理這些請求,而後返回響應。響應的格式一般是JSON或XML。瀏覽器
在這種類型的Web API裏,比較流行的是這三種:REST,RPC和GraphQL。緩存
REST全稱是Representational State Transfer 表述性狀態傳遞。REST多是如今最流行的一種Web API。安全
REST的核心就是資源,一個資源就是能夠被標識的實體,它有名稱和地址。服務器
REST API就是把數據以資源的形式暴露出來,並使用標準的HTTP方法來表明建立、讀取、更新和刪除資源等事務。數據結構
REST API有一些規則和約束,這裏我就簡單的寫一下(以前的文章有詳細描述):工具
資源都是URL的一部分,例如/persons性能
針對每一個資源一般都會有兩個URL被實現:「/persons」表示資源的集合,「/person/321」表示特定的一個資源3d
在資源裏,使用名詞而不是動詞,例如 /getUserInfo/123 這就不對了,應該是 /users/123代理
HTTP方法代表了要執行的動做,不一樣的HTTP方法做用於同一個URL上可實現不一樣的功能:blog
建立 -- POST
讀取 -- GET
總體更新 -- PUT
局部更新 -- PATCH
刪除 -- DELETE
服務器會返回標準的HTTP狀態碼,來表示請求成功或者失敗,以及緣由。一般2xx表示成功,3xx表示資源被移動了,4xx表示客戶端引發的錯誤,5xx表示服務器端引發的錯誤。
若是兩個資源有主從關係,那麼子資源最好不採用頂級資源的URL,而是採用主資源的子資源URL地址。例如Province和City就是主從關係,那麼City資源的URL應該是:/provinces/{provinceId}/cities,/provinces/{provinceId}/cities/{cityId}
非CRUD操做
API不免會有一個非CRUD的操做,例如「存檔」這個操做。這時候咱們能夠採起如下幾種辦法:
把這個動做做爲資源的一個字段。例如把「存檔」做爲輸入參數傳遞到API
做爲子資源。例如 /repos/{repoId}/issues/{issueId}/archive
直接使用動詞。實在不行了,就用動詞吧,例如 /search/params?......
Remote Procedure Call。RPC是一種比較簡單的API,客戶端直接會執行另外一個服務器上的代碼。
REST是關於資源的,而RPC就是關於動做的。
在RPC裏,客戶端一般是把方法名和參數傳遞給服務器,而後服務器返回JSON或XML。
RPC的規則比較少:
端點要包含被執行操做的名字
使用合理的HTTP動詞,GET用於讀取,POST用於其它類型。
RPC適用於那種沒法用CRUD封裝的動做,或者其影響和資源無關的動做。
RPC不只限於HTTP,還有其它協議能夠支持,例如Apache Thrift和gRPC。
GraphQL 是 API的查詢語言。最近愈來愈火。它由Facebook於2012年開始開發,2015年被開源了。
GraphQL容許客戶端定義須要獲得的數據結構,服務器精確的返回所需的數據結構,例如:
與REST和RPC不一樣,GraphQL API只須要一個端點;它也不須要使用不一樣的HTTP動詞,它只使用POST,你須要在JSON body裏面指定是要執行查詢仍是修改。
相對REST和RPC,GraphQL有下面幾個優點:
節省了多重的請求往返,GraphQL能夠一次把所需的關聯數據所有查詢出來。不會存在例如N+1這樣的問題
避免了API版本問題。你能夠隨時添加字段和類型,不會影響現有的查詢。能夠標記棄用。經過Log能夠追蹤出哪些字段被誰使用,若是字段沒人再去使用,就能夠移除它了。
Payload比較小。REST和RPC的響應都包含客戶端發送一些不須要的數據。而使用GraphQL的話,客戶端獲得的響應就是它所請求的那些東西,很少很多。
強類型。GraphQL是強類型的,開發時有類型檢查能保證查詢的正確性和合理性。
內省(Introspection)。像REST,就須要安裝Swagger等工具來幫助瀏覽API。而GraphQL自己就具有可發現性。它還帶有一個瀏覽器內的IDE用來瀏覽GraphQL API。下圖就是Github的GraphQL API:
GraphQL的缺點就是它爲服務器添加了許多複雜性,服務器須要額外的工做來處理這些複雜的查詢。根據查詢內容的不一樣,性能也是一個變數.
針對CRUD類的API,使用REST
針對暴露不少動做的API,使用RPC
當你須要查詢的靈活性以及維護的連續性時,使用GraphQL
針對用請求-響應式API,若是服務的數據常常變化,那麼響應就可能沒法保持新鮮了。開發者若是想與變化的數據保持同步,就只能對API進行polling操做了。
可是若是poll的頻率較低,客戶端仍有可能沒法得到從上次poll到如今全部的數據事件。若是poll的頻率較高,還特別浪費資源。
因此咱們須要實時的分享事件的數據,一般使用下面三種機制:WebHook,WebSocket,HTTP Streaming。
WebHook就是一個接收HTTP POST(或GET,PUT,DELETE)的URL。一個實現了WebHook的API提供商就是在當事件發生的時候會向這個配置好的URL發送一條信息。與請求-響應式不一樣,使用WebHook,你能夠實時接受到變化。
下面是Polling和Webhook的比較:
WebHook很是適合於從一個服務器向另一個服務器分享實時數據。
可是實現WebHook,也引入了新的複雜性:
失敗和重試。爲了保證WebHook被成功的傳輸,你須要構建一個能夠再發生錯誤時進行重試操做的系統。
安全性。對於安全的調用REST API,如今的方案都比較成熟;而對於WebHook來講,這方面依然在探索中前進。
防火牆。防火牆後運行的應用能夠經過HTTP訪問API,可是它們可能沒法接收入站的流量。因此這是一個很大的問題。
噪聲。一般每一個WebHook調用表明了一個事件,但當短期內發生了成千上萬個事件的時候,再經過WebHook來傳輸,就可能會有噪音。
WebSocket這個協議,它經過一個TCP協議創建一個雙向全雙工的流式通訊。WebSocket一般用在客戶端和服務器之間的通訊,也能夠用在服務器之間的通訊。
ASP.NET Core SignalR就是優先使用該協議。
WebSocket支持全雙工(服務器和客戶端能夠同時雙向通訊),並且開銷不高。常用的端口式80或443,這樣就很容易穿過防火牆了。
WebSocket特別適合於快速的,現場的路i數據和長鏈接。
若是鏈接掛掉了,客戶端會嘗試從新初始化鏈接。可是WebSocket有一些擴展性的問題,由於若是在線的客戶端太多,那麼服務器端就須要維持這些客戶端打開的鏈接。
使用請求-響應式API,客戶端發送一個請求,服務器端返回一個響應,這個響應的長度是有限的。
而使用HTTP Streaming,服務器端能夠在一個由客戶端打開的長生存的鏈接裏持續的推送新數據。
爲了讓數據經過一個可長時間存在的鏈接上進行傳輸,有兩個方案:
首先可讓服務器把Transfer-Encoding這個Header設爲chunked。這表示客戶端是按塊接收數據的,塊與塊之間用換行符分割:「\r\n」。
另外一個選項是經過Server-Sent Events (SSE)來進行流數據。這個比較適合於瀏覽器內的客戶端,由於這樣它們就可使用標準的EventSource API了。(SignalR在沒法使用WebSocket的時候就會使用SSE)
HTTP Streaming用起來好像很容易,可是有個問題,是關於緩存的。客戶端和代理常常會有緩存的限制。由於只有達到某個閾值以後,它們纔會把數據渲染給應用。
若是想要進行服務器間的實時事件通訊,能夠選擇WebHooks
若是須要瀏覽器和服務器間的雙向實時通訊,能夠選擇WebSocket
若是須要使用簡單的HTTP進行單向通訊,可使用HTTP Streaming