1. 程式人生 > 程式設計 >如何設計Web API?

如何設計Web API?

大多數現代的Web應用程式都公開了客戶端可以用來與應用程式互動的API。精心設計的Web API應該旨在支援:

  • 平臺獨立性。無論內部如何實現API,任何客戶端都應該能夠呼叫API。這需要使用標準協議,並具有一種機制,使客戶端和Web服務可以就要交換的資料格式達成一致。

  • 服務演進。Web API應該能夠獨立於客戶端應用程式進行演化和新增功能。隨著API的發展,現有的客戶端應用程式應繼續執行而無需修改。所有功能都應該是可發現的,以便客戶端應用程式可以充分使用它。

本文介紹了設計Web API時應考慮的問題。

REST簡介

在2000年,羅伊·菲爾丁(Roy Fielding)提出了代表性狀態轉移(REST)作為設計Web服務的體系結構方法。REST是一種用於構建基於超媒體的分散式系統的體系結構樣式。REST獨立於任何底層協議,不一定與HTTP繫結。但是,大多數常見的REST實現使用HTTP作為應用程式協議,並且本指南重點介紹為HTTP設計REST API。

REST相對於HTTP的主要優勢在於它使用開放標準,並且不會將API或客戶端應用程式的實現繫結到任何特定的實現。例如,REST Web服務可以用ASP.NET編寫,並且客戶端應用程式可以使用可以生成HTTP請求並解析HTTP響應的任何語言或工具集。

以下是使用HTTP的RESTful API的一些主要設計原則:

  • REST API是圍繞

    資源設計的,資源是客戶端可以訪問的任何型別的物件,資料或服務。

  • 資源具有

    識別符號,它是唯一標識該資源的URI。例如,特定客戶訂單的URI可能是: https://www.abc.com/orders/1

  • 客戶端通過交換資源

    表示與服務互動。許多Web API使用JSON作為交換格式。例如,對上面列出的URI的GET請求可能返回此響應主體(json):
    {"orderId":1,"orderValue":99.90,"productId":1,"quantity":1}

  • REST API使用統一的介面,這有助於使客戶端和服務實現脫鉤。對於基於HTTP構建的REST API,統一介面包括使用標準HTTP動詞對資源執行操作。最常見的操作是GET,POST,PUT,PATCH和DELETE。

  • REST API使用無狀態請求模型。HTTP請求應該是獨立的,並且可以以任何順序發生,因此在請求之間保留瞬態資訊是不可行的。資訊儲存的唯一位置是資源本身,每個請求都應該是原子操作。此約束使Web服務具有高度可伸縮性,因為不需要在客戶端和特定伺服器之間保留任何親緣關係。任何伺服器都可以處理來自任何客戶端的任何請求。也就是說,其他因素可能會限制可伸縮性。例如,許多Web服務寫入後端資料儲存,這可能很難擴充套件。

  • REST API由表示形式中包含的超媒體連結驅動。例如,以下顯示了訂單的JSON表示形式。它包含獲取或更新與訂單關聯的客戶的連結。

{ "orderID":3, "productID":2, "quantity":4, "orderValue":16.60, "links": [ {"rel":"product","href":"https://adventure-works.com/customers/3","action":"GET" }, {"rel":"product","action":"PUT" } ] }

2008年,倫納德·理查森(Leonard Richardson)為Web API 提出了以下成熟度模型:

  • 級別0:定義一個URI,並且所有操作都是對此URI的POST請求。

  • 級別1:為單個資源建立單獨的URI。

  • 級別2:使用HTTP方法定義對資源的操作。

  • 級別3:使用超媒體(HATEOAS,如下所述)。

根據Fielding的定義,級別3對應於真正的RESTful API。實際上,許多已釋出的Web API都屬於2級左右。

圍繞資源組織API

著重於Web API公開的業務實體。例如,在電子商務系統中,主要實體可能是客戶和訂單。建立訂單可以通過傳送包含訂單資訊的HTTP POST請求來實現。HTTP響應指示訂單是否成功下達。如果可能,資源URI應基於名詞(資源)而不是動詞(對資源的操作)。

https://www.abc.com/orders // Goodhttps://www.abc.com/create-order // Avoid複製程式碼

資源不必基於單個物理資料項。例如,訂單資源可能在內部實現為關係資料庫中的多個表,但作為單個實體呈現給客戶。避免建立僅反映資料庫內部結構的API。REST的目的是為實體以及應用程式可以在這些實體上執行的操作建模。客戶不應接觸內部實現。

實體通常被組合到集合中(訂單,客戶)。集合是與集合中專案無關的資源,並且應具有自己的URI。例如,以下URI可能代表訂單的集合:

https://www.abc.com/orders

向集合URI傳送HTTP GET請求可檢索集合中的專案列表。集合中的每個專案都有自己的唯一URI。對商品URI的HTTP GET請求返回該商品的詳細資訊。

在URI中採用一致的命名約定。通常,對引用集合的URI使用複數名詞會有所幫助。將集合和專案的URI組織到層次結構中是一個好習慣。例如,/customers是通往客戶集合/customers/5的路徑,是通往ID等於5的顧客的路徑。這種方法有助於保持Web API的直觀性。另外,許多Web API框架都可以基於引數化URI路徑來路由請求,因此您可以為path定義路由/customers/{id}

還請考慮不同型別的資源之間的關係以及如何暴露這些關聯。例如,/customers/5/orders可能代表客戶5的所有訂單。您也可以朝另一個方向前進,並使用URI之類的URI表示從訂單到客戶的關聯/orders/99/customer。但是,將模型擴充套件得太遠可能難以實施。更好的解決方案是在HTTP響應訊息的正文中提供指向關聯資源的可導航連結。

在更復雜的系統中,提供URI使客戶端能夠瀏覽多個級別的關係(例如)可能很誘人/customers/1/orders/99/products。但是,如果將來資源之間的關係發生變化,則這種複雜性級別可能難以維護,並且很難保持靈活性。相反,請嘗試使URI保持相對簡單。一旦應用程式引用了資源,就應該可以使用該引用來查詢與該資源有關的專案。可以將前面的查詢替換為URI,/customers/1/orders以查詢客戶1的所有訂單,然後/orders/99/products查詢此訂單中的產品。

另一個因素是,所有Web請求都會對Web伺服器施加負載。請求越多,負載越大。因此,請嘗試避免使用暴露大量小資源的“聊天” Web API。這樣的API可能要求客戶端應用程式傳送多個請求以查詢其所需的所有資料。取而代之的是,您可能想對資料進行非規範化並將相關資訊合併為更大的資源,這些資源可以通過單個請求檢索。但是,您需要在此方法與獲取客戶端不需要的資料的開銷之間取得平衡。檢索大物件可能會增加請求的延遲,並導致額外的頻寬成本。

避免在Web API和基礎資料來源之間引入依賴關係。例如,如果您的資料儲存在關係資料庫中,則Web API不需要將每個表都顯示為資源的集合。實際上,這可能是一個糟糕的設計。相反,可以將Web API視為資料庫的抽象。如有必要,請在資料庫和Web API之間引入一個對映層。這樣,客戶端應用程式就不會與基礎資料庫方案的更改保持隔離。

最後,可能無法將Web API實施的每個操作對映到特定資源。您可以通過呼叫功能的HTTP請求來處理此類

非資源方案,並將結果作為HTTP響應訊息返回。例如,實現簡單的計算器操作(例如加法和減法)的Web API可以提供將這些操作公開為偽資源的URI,並使用查詢字串來指定所需的引數。例如,對URI / add? operand1 = 99&operand2 = 1的GET請求將返回帶有包含值100的正文的響應訊息。但是,僅保留使用這些形式的URI。

根據HTTP方法定義操作

HTTP協議定義了許多將語義分配給請求的方法。大多數RESTful Web API使用的常見HTTP方法是:

  • GET以指定的URI檢索資源的表示形式。響應訊息的正文包含所請求資源的詳細資訊。

  • POST在指定的URI處建立一個新資源。請求訊息的正文提供了新資源的詳細資訊。請注意,POST也可以用於觸發實際上並不建立資源的操作。

  • PUT可以建立或替換指定URI處的資源。請求訊息的正文指定要建立或更新的資源。

  • PATCH執行資源的部分更新。請求主體指定要應用於資源的一組更改。

  • DELETE刪除指定URI處的資源。

特定請求的效果應取決於資源是集合還是單個專案。下表使用電子商務示例總結了大多數RESTful實現所採用的通用約定。並非所有這些請求都可以實現-這取決於特定的方案。

資源資源 開機自檢 得到 刪除
/顧客 建立新客戶 檢索所有客戶 批量更新客戶

刪除所有

客戶

/客戶/ 1 錯誤 檢索客戶1的詳細資訊 更新客戶1的詳細資訊(如果存在)

刪除客

戶1

/ customers / 1 /訂單 為客戶1建立新訂單 檢索客戶1的所有訂單 批量更新客戶1的訂單 刪除客戶1的所有訂單

POST,PUT和PATCH之間的差異可能令人困惑。

  • POST請求建立資源。伺服器為新資源分配一個URI,並將該URI返回給客戶端。在REST模型中,您經常將POST請求應用於集合。新資源將新增到集合中。POST請求也可以用於提交資料以處理現有資源,而無需建立任何新資源。

  • PUT請求建立資源

    或更新現有資源。客戶端指定資源的URI。請求主體包含資源的完整表示。如果具有此URI的資源已存在,則將其替換。否則,如果伺服器支援,則建立一個新資源。PUT請求最常應用於單個專案(例如特定客戶)而不是集合的資源。伺服器可能支援更新,但不支援通過PUT建立。是否支援通過PUT建立取決於客戶端是否可以在資源存在之前為資源有意義地分配URI。如果不是,則使用POST建立資源,並使用PUT或PATCH更新。

  • PATCH請求對現有資源執行

    部分更新。客戶端指定資源的URI。請求主體指定一組更改以應用於資源。這可能比使用PUT更有效,因為客戶端僅傳送更改,而不傳送資源的完整表示。從技術上講,如果伺服器支援,PATCH也可以建立新資源(通過為“空”資源指定一組更新)。

PUT請求必須是冪等的。如果客戶端多次提交相同的PUT請求,則結果應始終相同(將使用相同的值修改相同的資源)。POST和PATCH請求不保證是冪等的。

符合HTTP語義

本節描述了設計符合HTTP規範的API的一些典型注意事項。但是,它沒有涵蓋所有可能的細節或場景。如有疑問,請查閱HTTP規範。

媒體型別

如前所述,客戶端和伺服器交換資源的表示形式。例如,在POST請求中,請求主體包含要建立的資源的表示形式。在GET請求中,響應主體包含獲取的資源的表示形式。

在HTTP協議中,通過使用

媒體型別(也稱為MIME型別)來指定格式。對於非二進位制資料,大多數Web API支援JSON(媒體型別= application / xml),可能還支援XML(媒體型別= application / xml)。

請求或響應中的Content-Type標頭指定表示的格式。這是一個包含JSON資料的POST請求示例:

POSThttps://adventure-works.com/orders HTTP/1.1

Content-Type: application/json; charset=utf-8

Content-Length: 57

{"Id":1,"Name":"Gizmo","Category":"Widgets","Price":1.99}

如果伺服器不支援媒體型別,則應返回HTTP狀態碼415(不支援的媒體型別)。

客戶端請求可以包含一個Accept標頭,該標頭包含客戶端將在響應訊息中從伺服器接受的媒體型別列表。例如:

GEThttps://adventure-works.com/orders/2 HTTP/1.1 Accept: application/json

如果伺服器無法匹配列出的任何媒體型別,則伺服器應返回HTTP狀態程式碼406(不可接受)。

GET方法

成功的GET方法通常返回HTTP狀態程式碼200(確定)。如果找不到資源,則該方法應返回404(未找到)。

POST方法

如果POST方法建立新資源,它將返回HTTP狀態程式碼201(已建立)。新資源的URI包含在響應的Location標頭中。響應主體包含資源的表示形式。

如果該方法進行了一些處理但未建立新資源,則該方法可以返回HTTP狀態程式碼200,並將操作結果包括在響應主體中。或者,如果沒有要返回的結果,則該方法可以返回沒有響應正文的HTTP狀態程式碼204(無內容)。

如果客戶端將無效資料放入請求中,則伺服器應返回HTTP狀態程式碼400(錯誤請求)。響應主體可以包含有關錯誤的其他資訊,也可以包含提供更多詳細資訊的URI連結。


PUT方法

如果PUT方法建立新資源,則與POST方法一樣,它返回HTTP狀態程式碼201(已建立)。如果該方法更新了現有資源,則返回200(確定)或204(無內容)。在某些情況下,可能無法更新現有資源。在這種情況下,請考慮返回HTTP狀態程式碼409(衝突)。


考慮實現批量HTTP PUT操作,該操作可以批量更新集合中的多個資源。PUT請求應指定集合的URI,請求主體應指定要修改的資源的詳細資訊。這種方法可以幫助減少聊天情況並提高效能。

Delete方法

如果刪除操作成功,則Web伺服器應使用HTTP狀態程式碼204進行響應,指示該過程已成功處理,但是響應主體不包含其他資訊。如果資源不存在,則Web伺服器可以返回HTTP 404(未找到)。

非同步操作

有時POST,PUT,PATCH或DELETE操作可能需要一些處理才能完成。如果在傳送響應到客戶端之前等待完成,則可能會導致無法接受的延遲。如果是這樣,請考慮使操作非同步。返回HTTP狀態碼202(已接受)以指示請求已接受處理,但未完成。

您應該公開一個返回非同步請求狀態的端點,以便客戶端可以通過輪詢狀態端點來監視狀態。在202響應的Location標頭中包含狀態終結點的URI。例如:

HTTP/1.1 202 Accepted

Location: /api/status/12345

如果客戶端將GET請求傳送到此端點,則響應應包含請求的當前狀態。可選地,它還可以包括估計的完成時間或取消操作的連結。

HTTP/1.1 200 OK

Content-Type: application/json

{

"status":"In progress","link": { "rel":"cancel","method":"delete","href":"/api/status/12345" } }

如果非同步操作建立了新資源,則該操作完成後,狀態端點應返回狀態程式碼303。在303響

應中,包括一個Location標頭,該標頭提供了新資源的URI:

HTTP/1.1 303 See Other

Location: /api/orders/12345

篩選和分頁資料

當僅需要一部分資訊時,通過單個URI公開資源集合可能導致應用程式獲取大量資料。例如,假設客戶端應用程式需要查詢成本超過特定值的所有訂單。它可能會從

/ orders URI中檢索所有訂單,然後在客戶端過濾這些訂單。顯然,此過程效率很低。它浪費了網路頻寬和託管Web API的伺服器上的處理能力。

相反,API可以允許在URI的查詢字串中傳遞過濾器,例如

/ orders? minCost = n。然後,Web API負責解析和處理minCost查詢字串中的引數,並在伺服器端返回過濾後的結果。

收集資源上的GET請求可能會返回大量專案。您應該設計一個Web API來限制任何單個請求返回的資料量。考慮支援查詢字串,這些字串指定要檢索的最大專案數以及集合中的起始偏移量。例如:

/orders?limit=25&offset=50

還應考慮對返回的專案數施加上限,以幫助防止拒絕服務攻擊。為了幫助客戶端應用程式,返回分頁資料的GET請求還應該包括某種形式的元資料,以指示集合中可用資源的總數。

通過提供將欄位名作為值的排序引數,例如

/ orders? sort = ProductID,可以使用類似的策略對資料進行排序。但是,此方法可能會對快取產生負面影響,因為查詢字串引數形成了資源識別符號的一部分,該識別符號被許多快取實現用作快取資料的鍵。

如果每個專案包含大量資料,則可以擴充套件此方法以限制為每個專案返回的欄位。例如,您可以使用查詢字串引數,該引數接受以逗號分隔的欄位列表,例如

/ orders? fields = ProductID,Quantity。

在查詢字串中為所有可選引數提供有意義的預設值。例如,如果實現分頁,則將引數設定limit為10,將offset引數設定為0,如果實現排序,則將sort引數設定為資源的鍵,fields如果支援投影,則將引數設定為資源中的所有欄位。

支援對大型二進位制資源的部分響應

資源可能包含較大的二進位制欄位,例如檔案或影象。為了克服由不可靠和間歇性連線引起的問題並改善響應時間,請考慮使此類資源能夠分塊檢索。為此,Web API應該支援用於大資源的GET請求的Accept-Ranges標頭。此標頭表示GET操作支援部分請求。客戶端應用程式可以提交GET請求,該請求返回指定為位元組範圍的資源子集。

另外,請考慮為這些資源實現HTTP HEAD請求。HEAD請求與GET請求相似,不同之處在於,它僅返回描述資源的HTTP標頭,且訊息正文為空。客戶端應用程式可以發出HEAD請求,以確定是否通過使用部分GET請求來獲取資源。例如:

HEADhttps://adventure-works.com/products/10?fields=productImage HTTP/1.1

這是示例響應訊息:

HTTP/1.1 200 OK

Accept-Ranges: bytes

Content-Type: image/jpeg

Content-Length: 4580


Content-Length標頭提供資源的總大小,Accept-Ranges標頭指示相應的GET操作支援部分結果。客戶端應用程式可以使用此資訊以較小的塊來檢索影象。第一個請求通過使用Range標頭獲取前2500個位元組:

HTTP/1.1 303 See Other

Location: /api/orders/12345

篩選和分頁資料

當僅需要一部分資訊時,通過單個URI公開資源集合可能導致應用程式獲取大量資料。例如,假設客戶端應用程式需要查詢成本超過特定值的所有訂單。它可能會從

/ orders URI中檢索所有訂單,然後在客戶端過濾這些訂單。顯然,此過程效率很低。它浪費了網路頻寬和託管Web API的伺服器上的處理能力。

相反,API可以允許在URI的查詢字串中傳遞過濾器,例如

/ orders? minCost = n。然後,Web API負責解析和處理minCost查詢字串中的引數,並在伺服器端返回過濾後的結果。

收集資源上的GET請求可能會返回大量專案。您應該設計一個Web API來限制任何單個請求返回的資料量。考慮支援查詢字串,這些字串指定要檢索的最大專案數以及集合中的起始偏移量。例如:

/orders?limit=25&offset=50

還應考慮對返回的專案數施加上限,以幫助防止拒絕服務攻擊。為了幫助客戶端應用程式,返回分頁資料的GET請求還應該包括某種形式的元資料,以指示集合中可用資源的總數。

通過提供將欄位名作為值的排序引數,例如

/ orders? sort = ProductID,可以使用類似的策略對資料進行排序。但是,此方法可能會對快取產生負面影響,因為查詢字串引數形成了資源識別符號的一部分,該識別符號被許多快取實現用作快取資料的鍵。

如果每個專案包含大量資料,則可以擴充套件此方法以限制為每個專案返回的欄位。例如,您可以使用查詢字串引數,該引數接受以逗號分隔的欄位列表,例如

/ orders? fields = ProductID,Quantity。

在查詢字串中為所有可選引數提供有意義的預設值。例如,如果實現分頁,則將引數設定limit為10,將offset引數設定為0,如果實現排序,則將sort引數設定為資源的鍵,fields如果支援投影,則將引數設定為資源中的所有欄位。

支援對大型二進位制資源的部分響應

資源可能包含較大的二進位制欄位,例如檔案或影象。為了克服由不可靠和間歇性連線引起的問題並改善響應時間,請考慮使此類資源能夠分塊檢索。為此,Web API應該支援用於大資源的GET請求的Accept-Ranges標頭。此標頭表示GET操作支援部分請求。客戶端應用程式可以提交GET請求,該請求返回指定為位元組範圍的資源子集。

另外,請考慮為這些資源實現HTTP HEAD請求。HEAD請求與GET請求相似,不同之處在於,它僅返回描述資源的HTTP標頭,且訊息正文為空。客戶端應用程式可以發出HEAD請求,以確定是否通過使用部分GET請求來獲取資源。例如:

HEADhttps://adventure-works.com/products/10?fields=productImage HTTP/1.1
這是示例響應訊息:

HTTP/1.1 200 OK


Accept-Ranges: bytes

Content-Type: image/jpeg

Content-Length: 4580


Content-Length標頭提供資源的總大小,Accept-Ranges標頭指示相應的GET操作支援部分結果。客戶端應用程式可以使用此資訊以較小的塊來檢索影象。第一個請求通過使用Range標頭獲取前2500個位元組:

GEThttps://adventure-works.com/products/10?fields=productImage HTTP/1.1

Range: bytes=0-2499

響應訊息通過返回HTTP狀態程式碼206指示這是部分響應。Content-Length標頭指定了訊息正文中返回的實際位元組數(不是資源的大小),而Content-Range標頭指示了哪個響應。這是資源的一部分(4580中的位元組0-2499):

HTTP/1.1 206 Partial Content


Accept-Ranges: bytes

Content-Type: image/jpeg

Content-Length: 2500

Content-Range: bytes 0-2499/4580

來自客戶端應用程式的後續請求可以檢索資源的其餘部分。

使用HATEOAS啟用對相關資源的導航

REST背後的主要動機之一是,無需事先了解URI方案,就應該可以瀏覽整個資源集。每個HTTP GET請求應通過響應中包含的超連結返回查詢與請求的物件直接相關的資源所必需的資訊,並且還應向其提供描述這些資源中的每一個可用操作的資訊。此原理稱為HATEOAS,或稱為應用程式狀態引擎的超文字。該系統實際上是一個有限狀態機,對每個請求的響應都包含從一種狀態轉移到另一種狀態所需的資訊。不需要其他資訊。

對RESTful Web API進行版本控制

Web API保持靜態的可能性很小。隨著業務需求的變化,可能會新增新的資源集合,資源之間的關係可能會更改,並且資源中的資料結構可能會被修改。儘管更新Web API以處理新的或不同的要求是一個相對簡單的過程,但是您必須考慮此類更改將對使用Web API的客戶端應用程式產生的影響。問題在於,儘管設計和實現Web API的開發人員可以完全控制該API,但是開發人員對客戶端應用程式的控制程度不同,該客戶端應用程式可以由遠端執行的第三方組織構建。

通過版本控制,Web API可以指示其公開的功能和資源,並且客戶端應用程式可以提交針對功能或資源的特定版本的請求。以下各節描述了幾種不同的方法,每種方法都有其自身的優點和取捨。

沒有版本控制

這是最簡單的方法,對於某些內部API可能是可接受的。重大更改可以表示為新資源或新連結。向現有資源新增內容可能不會帶來重大變化,因為不希望看到此內容的客戶端應用程式將忽略它。

例如,到URI的請求https://www.abc.com/customers/3應該返回單個客戶的含有細節idname以及address由所述客戶端應用程式預期欄位:

HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8 {"id":3,"name":"Contoso LLC","address":"1 Microsoft Way Redmond WA 98053"}


如果將該DateCreated欄位新增到客戶資源的架構,則響應將如下所示:

HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8

{"id":3,"dateCreated":"2014-09-04T12:11:38.0376089Z","address":"1 Microsoft Way Redmond WA 98053"}

如果現有的客戶端應用程式能夠忽略無法識別的欄位,則它們可能會繼續正常執行,而新的客戶端應用程式可以設計為處理此新欄位。但是,如果對資源的架構進行了更根本的更改(例如,刪除或重新命名欄位),或者資源之間的關係發生了更改,則這些更改可能構成重大更改,從而阻止現有客戶端應用程式正常執行。在這些情況下,您應該考慮使用以下方法之一。

URI版本控制

每次您修改Web API或更改資源架構時,您都會為每個資源的URI新增一個版本號。先前存在的URI應該繼續像以前一樣操作,返回符合其原始架構的資源。

延伸的前面的例子,如果該address欄位被重組為包含地址的每個組成部分(如子場streetAddresscitystate,和zipCode),這個版本的資源的可通過URI暴露包含一個版本號,如 https://adventure-works.com/v2/customers/3

HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8

{"id":3,"address":{"streetAddress":"1 Microsoft Way","city":"Redmond","state":"WA","zipCode":98053}

這種版本控制機制非常簡單,但是取決於伺服器將請求路由到適當的端點。但是,隨著Web API通過多次迭代成熟,並且伺服器必須支援許多不同的版本,它可能變得笨拙。同樣,從純粹主義者的角度來看,在所有情況下,客戶端應用程式都在提取相同的資料(客戶3),因此URI不應真正取決於版本。此方案還使HATEOAS的實現複雜化,因為所有連結都需要在其URI中包括版本號。

查詢字串版本控制

您可以使用附加到HTTP請求的查詢字串中的引數(例如)來指定資源的版本,而不是提供多個URI https://www.abc.com/customers/3?version=2。如果較舊的客戶端應用程式省略了版本引數,則該版本引數應預設為有意義的值,例如1。

這種方法具有語義優勢,即始終從相同的URI中檢索相同的資源,但是它取決於處理請求的程式碼以解析查詢字串併發送回適當的HTTP響應。這種方法還遭受與URI版本控制機制相同的實現HATEOAS的複雜性。

標頭版本控制

您可以實現一個指示資源版本的自定義標頭,而不是將版本號附加為查詢字串引數。這種方法要求客戶端應用程式將適當的標頭新增到任何請求,儘管如果省略了版本標頭,則處理客戶端請求的程式碼可以使用預設值(版本1)。以下示例使用名為

Custom-Header的自定義標頭。此標頭的值指示Web API的版本。


版本1:

GEThttps://www.abc.com/customers/3 HTTP/1.1

Custom-Header: api-version=1


HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8

{"id":3,"address":"1 Microsoft Way Redmond WA 98053"}


版本2:

GEThttps://www.abc.com/customers/3 HTTP/1.1

Custom-Header: api-version=2


HTTP/1.1 200 OK

Content-Type: application/json; charset=utf-8

{"id":3,"zipCode":98053}}

與前兩種方法一樣,實現HATEOAS要求在任何連結中包括適當的自定義標頭。

媒體型別版本控制

當客戶端應用程式將HTTP GET請求傳送到Web伺服器時,應按照本指南前面所述,指定它可以使用Accept標頭處理的內容格式。通常,

Accept標頭的目的是允許客戶端應用程式指定響應的主體是XML,JSON還是客戶端可以解析的其他常見格式。但是,可以定義包括資訊的自定義媒體型別,該資訊使客戶端應用程式能夠指示期望的資源版本。以下示例顯示了一個請求,該請求使用值application / vnd.adventure-works.v1 + json指定一個Accept報頭。該vnd.adventure-works.v1元素向Web伺服器指示應返回資源的版本1,而json元素則指定響應主體的格式應為JSON:

GEThttps://adventure-works.com/customers/3 HTTP/1.1

Accept: application/vnd.adventure-works.v1+json


處理請求的程式碼負責處理

Accept報頭並儘可能地兌現它(客戶端應用程式可以在

Accept報頭中指定多種格式,在這種情況下,Web伺服器可以為響應正文選擇最合適

的格式)。Web伺服器通過使用Content-Type標頭確認響應正文中的資料格式:

HTTP/1.1 200 OK

Content-Type: application/vnd.adventure-works.v1+json; charset=utf-8

{"id":3,"address":"1 Microsoft Way Redmond WA 98053"}

如果Accept標頭未指定任何已知的媒體型別,則Web伺服器可以生成HTTP 406(不可接受)響應訊息或返回具有預設媒體型別的訊息。

這種方法可以說是最純粹的版本控制機制,並且很自然地適合HATEOAS,後者可以在資源連結中包括相關資料的MIME型別。

注意:  選擇版本控制策略時,還應考慮對效能的影響,尤其是Web伺服器上的快取。URI版本控制和查詢字
符串版本控制方案是快取友好的,因為相同的URI /查詢字串組合每次都引用相同的資料。標頭版本控制
和媒體型別版本控制機制通常需要其他邏輯來檢查自定義標頭或“接  受”標頭中的值。在大規模環境中,
許多使用不同版本的Web API的客戶端可能會  在伺服器端快取中導致大量重複資料。如果客戶端應用程式
通過實現快取的代理與Web伺服器通訊,並且僅在當前不將請求資料的副本儲存在其快取中的情況下將請求
轉發到Web伺服器,則此問題可能變得很嚴重。複製程式碼


感謝閱讀!


喜歡本文的朋友,歡迎關注“isevena