restful
什么是API
API全稱Aplication Programming Itererface即應用程序編程接口, 我們在開發應用程序時經常用到。API作為接口,用來“連接”兩個不同的系統,並使其中一方為另一 方提供服務,比如在操作系統上運行的應用程序能夠訪問操作系統所提供的API,並通過這些API來調用操,作系統的各種功能。因此,API 是一個系統向外暴露或公開的一套接口, 通過這些接口,外部應用程序能夠訪問該系統。在Web應用程序中,Web API具有同樣的特性,它作為一個Web應用程序,向外提供了,在Web應用程序中,Web API具有同樣的特性,它作為一個Web應用程序,向外提供了一些接口, 這些接口的功能通常是對數據進行操作,一些接口, 這些接口的功能通常是對數據進行操作(如獲取或修改數據等),它們能夠被外部應用程序,比如桌面應用程序、手機應用甚至其他Web應用程序(如ASP.NET Core MVC視圖應用、單頁Web應用)等訪問並調用。WebAPI能夠實現不同應用程序之間的訪問,它與平台或編程語言無關,可以使用不同的技術來構建Web API,如Java、.NET等;
什么是REST
REST(Representational State Transfer) 表述性傳遞狀態,Roy Fielding博士在2000年他的博士論文中提出來的一種軟件架構風格,作為一種web服務的設計與開發方式,Rest可以降低開發的復雜性,提高系統的可伸縮性。
REST是一種基於資源的架構風格,在REST中,資源(Resource)是最基本的概念任何能夠命名的對象都是資源,如:user,team,order,docment。他表示web服務要操作的一個實體,一個資源具有一個統一資源標識符。(Uniform Resource Identifier URI),如 users/123。通過資源能夠標識並訪問資源。
資源標識
主鍵編號進行標識
資源集合
除了單個資源外,資源集合表示多個相同類型的資源,如users。在系統設計時,不同的實體之間往往存在着某種關聯關系。如一個用戶有多個訂單。同樣,在REST中,這種關聯關系也能夠有資源之間的層次關系體現出來。如users/123/orders/1
由於REST資源為中心,因此REST接口的端點(Endpoint)均以資源或資源集合結尾,它不像其他形式的WEB服務一樣以動詞結尾,如api/GetUserInfo或者api/UpdateUserInfo。在REST中,對資源的動作或操作是通過HTTP方法來完成的。如下
GET http://api . domain. com/users/1234 查詢
PUT http://api . domain. com/users/1234 修改
上例中用到了兩個HTTP方法,分別為GET與PUT,它們的作用分別是獲取和更新指定資源,當請求方發起請求,修改了資源的狀態后,更新后的資源表述應返回給請求方,這也是表述性狀態傳遞的意義。
同時我們可以知道,REST是和HTTP有一定的關系,資源在服務的提供方和請求方之間進行傳遞。需要借助於協議來約定,比如協議所規定的消息格式等,而HTTP協議則是非常成熟且廣泛使用的網絡協議。事實上,HTTP協議完全滿足REST中所定義的約束。因此,REST可以輕松的使用HTTP協議及其中的功能(如TTP方法,HTTP消息等),並設計出松耦合的Web服務
REST約束
客戶端-服務端
客戶端-服務端約束體現了關注點分離原則,使客戶端與服務端各自能夠獨立實現並獨立開發,只要他們之間的接口不改變即可,客戶端可以使用不同的技術或編程語言。
統一接口
統一接口是設計任何RESTful服務的基礎,也是區別Rest風格與其他web服務風格的最主要體現,系統中多個組件(服務器,客戶端,以及可能存在的代理服務器等)都依賴統一接口,分別由4個子約束組成
資源標識
users/123,orders/12,docment/12
通過表述操作資源
格式通常為json,xml,html等,最好是
json {user:{"id":123,"name":Tom}} xml
自描述信息
客戶端和服務端之前傳遞的每一條消息都應包含足夠的信息,這些信息不僅包含了資源的表述,也包含了資源表述的相關信息(格式和內容長度),甚至包含了資源相關的其他操作信息。
超媒體作為應用程序狀態引擎(HATEOAS)
服務器返回的資源表述中不僅要包含資源的表述,也應包含與之相關的鏈接,這些鏈接能夠對資源執行其他操作。比如當獲取資源時,返回的鏈接中,包含更新該資源,刪除資源等鏈接
分層系統
分層系統約束能夠使用網絡中介(如代理和網關)透明地部署到客戶端和服務端之間,只能能夠遵守並且使用前面提到的統一接口約束即可,客戶端和服務端都不知道網絡中介的存在。中間服務器主要用於增強安全,負載均衡和響應緩存等目的
緩存
緩存是web架構中重要的特性之一,客戶端和網絡中介均能夠緩存服務器返回的響應,因此當服務器返回響應時,應指明該響應的緩存特性,對響應進行緩存將有助於減少數據獲取延遲以及對服務器的請求,從而提高系統的性能。
無狀態
無狀態約束將指明服務器不會記錄或存儲客戶端的狀態信息,反之,這些狀態信息應有客戶端來保存並維護,因此客戶端對服務的請求不能依賴已發生的其他請求,當客戶端請求服務器時,必須在請求消息中包含所有與之相關的信息(如認證信息等)
按需編碼
按需編碼約束允許服務器臨時向客戶端返回可執行的程序代碼(如腳本等),返回這些代碼用戶為客戶端提供擴展或自定義的功能,由於客戶端必須理解並能夠執行服務器返回的代碼,因此這一約束增加了客戶端和服務器之間的耦合,同時,這一約束是可選的 。
Restful api設計
對於REST及其約束,將有助於我們設計RESTful服務或Restful API,
在關注點方面 RESTful api 主要是面向資源,RPC 面向功能 (Remote Produce Call 遠程過程調用)
在api端點方面,REST 的端點是名詞,是資源或資源集合,而RPC的端點是動詞、是方法名
在執行特點方面,REST對資源執行操作,RPC執行服務器上的方法
在返回結果方面,REST返回請求的資源,而RPC則返回調用方法的執行結果
什么是HTTP協議
超文本傳輸協議
1、URL 統一資源定義符
2、媒體類型
也就是說的內容類型,Content Type
3、http消息
也就是http之間交互的語言
3.1 起至行
3.2 HTTP消息頭
對於消息體的描述,和一些相關的配置
3.3 空行
3.4 HTTP消息體(資源,html表單)
4、http方法
GET POST PUT DELETE PATCH HEAD OPTIONS
GET 獲取資源
POST 創建資源
PUT 修改資源
DELETE 刪除資源
PATCH 資源部分更新 與 PUT 類似,但是是部分更新
HEAD 不會放回消息正文,和 GET類似
OPTIONS 方法用戶獲取資源支持的操作,
5、http消息頭
http請求頭
http響應頭
6、狀態碼
1XX : 信息
2XX : 成功
3XX :重定向
4XX:客戶端錯誤
5XX:服務端錯誤
rest最佳實踐
原則:
1、使用名詞對的復數表示一個資源集合,如api.domain.com/users
2、使用斜線“/”用來表示資源之間的層次關系,如api.domain.com/users/1234/orders
3、對資源的增,刪,改,查等操作名稱不應包含在URL中,反之應正確使用HTTP方法,比如,GET/deleteuser/1234(錯誤),DELETE users/1234(正確)
4、如果一個操作無法對應到資源的某個操作上,此時可以適當地在URI中包含動詞,但依然應該基於一個資源的標識符。例如:
PUT /users/1234/set-admin
DELETE /users/1234/set-admin
5、查詢字符串可以用來對資源進行篩選、搜索或分頁查詢等操作,如下所示
GET /users?role=admin
GET /users?searchQuery=abc
GET /users?pageSize=25&pageNumber=2
6、URI 中應盡量使用小寫字母
7、URI中可以使用中划線“-”來增加其可讀性,如使用“-”來代替空格
http://api.domain.com/blogs/this-is-my-first-post
8、URI中不應使用下划線
URI中通常會帶有下划線,以表示它是可點擊的,這個下划線將會使URI中下划線不可見,可以使用“-”代替
9、URL末尾不應包含斜線“/”
例如:/users/1234/ 錯誤 /users/1234 正確
restful API資源標識格式
JSON和XML為常用到的兩種資源表述格式,他們都可以用來傳遞數據,且都有簡潔,自描述的特點
restful api 版本
當api 發生了變化,比如資源表述內容有新增字段(字段或屬性)或系統添加了新資源類型時,應使用不同的版本來區別對API的更改,為 restful api 添加版本有以下4方式
1、使用urI 路徑 如 api/v1/users
2、使用查詢字符串,如 api/users?version=v1
3、使用自定義消息頭,如Accept-version:v1
4、使用Accept消息頭,如Accept:application/json;v=2.0
webapi
就是使用asp.net core使用c#創建Restful服務,就是webapi,如果要使用webapi控制器
webapi中的控制器是派生自ControllerBase的類,
ControllerBase類
不要通過從 Controller 類派生來創建 Web API 控制器。 Controller
派生自 ControllerBase
,並添加對視圖的支持,因此它用於處理 Web 頁面,而不是 Web API 請求。 此規則有一個例外:如果打算為視圖和 Web API 使用相同的控制器,則從 Controller
派生控制器。
ControllerBase
類提供了很多用於處理 HTTP 請求的屬性和方法。
例如,ControllerBase.CreatedAtAction
返回 201 狀態代碼:
下面是 ControllerBase
提供的方法的更多示例。
方法 | 說明 |
---|---|
BadRequest | 返回 400 狀態代碼。 |
NotFound | 返回 404 狀態代碼。 |
PhysicalFile | 返回文件。 |
TryUpdateModelAsync | 調用模型綁定。 |
TryValidateModel | 調用模型驗證。 |
特性
Microsoft.AspNetCore.Mvc 命名空間提供可用於配置 Web API 控制器的行為和操作方法的屬性。 下述示例使用屬性來指定受支持的 HTTP 操作動作和所有可返回的已知 HTTP 狀態代碼:
[HttpPost][ProducesResponseType(StatusCodes.Status201Created)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public ActionResult
{
pet.Id = _petsInMemoryStore.Any() ?
_petsInMemoryStore.Max(p => p.Id) + 1 : 1;
_petsInMemoryStore.Add(pet);
return CreatedAtAction(nameof(GetById), new { id = pet.Id }, pet);
}
特性 | 說明 |
---|---|
[[Route\] ] |
指定控制器或操作的 URL 模式。 |
[[Bind\] ] |
指定要包含的前綴和屬性,以進行模型綁定。 |
[[HttpGet\] ] |
標識支持 HTTP GET 操作謂詞的操作。 |
[[Consumes\] ] |
指定某個操作接受的數據類型。 |
[[Produces\] ] |
指定某個操作返回的數據類型。 |
ApiController特性
特定控制器上特性
[[ApiController\]
]屬性可應用於控制器類,以啟用下述 API 特定的固定行為:
必須有兼容性版本 2.2 或更高版本,才能使用“錯誤狀態代碼的問題詳細信息” 功能。 必須有兼容性版本 2.1 或更高版本,才能使用其他功能。
多個控制器上的特性
在多個控制器上使用該屬性的一種方法是創建通過 [ApiController]
屬性批注的自定義基控制器類。 下述示例展示了自定義基類以及從其派生的控制器:
[ApiController]
public class MyControllerBase : ControllerBase
{
}
[Produces(MediaTypeNames.Application.Json)]
[Route("[controller]")]
public class PetsController : MyControllerBase
程序集上特性
如果將兼容性版本設置為 2.2 或更高版本,則 [ApiController]
屬性可應用於程序集。 以這種方式進行注釋,會將 web API 行為應用到程序集中的所有控制器。 無法針對單個控制器執行選擇退出操作。 將程序集級別的屬性應用於 Startup
類兩側的命名空間聲明:
[assembly: ApiController]
namespace WebApiSample
{
public class Startup
{
...
}
}
特性路由要求
[ApiController]
屬性使屬性路由成為要求。 例如:
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
不能通過由 Startup.Configure
中的 UseEndpoints
、UseMvc 或 UseMvcWithDefaultRoute 定義的傳統路由訪問操作。
自動http 400響應
[ApiController]
屬性使模型驗證錯誤自動觸發 HTTP 400 響應。 因此,操作方法中不需要以下代碼:
if (!ModelState.IsValid)
{
return BadRequest(ModelState);
}
ASP.NET Core MVC 使用 ModelStateInvalidFilter 操作篩選器來執行上述檢查。
默認 BadRequest 響應
使用 2.1 的兼容性版本時,HTTP 400 響應的默認響應類型為 SerializableError。 下述請求正文是序列化類型的示例:
JSON
{
"": [
"A non-empty request body is required."
]
}
使用 2.2 或更高版本的兼容性版本時,HTTP 400 響應的默認響應類型為 ValidationProblemDetails。 下述請求正文是序列化類型的示例:
JSON
{
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|7fb5e16a-4c8f23bbfc974667.",
"errors": {
"": [
"A non-empty request body is required."
]
}
}
ValidationProblemDetails
類型:
- 提供計算機可讀的格式來指定 Web API 響應中的錯誤。
- 符合 RFC 7807 規范。
記錄自動 400 響應
請參閱如何對模型驗證錯誤記錄自動 400 響應 (aspnet/AspNetCore.Docs #12157)。
禁用自動 400 響應
若要禁用自動 400 行為,請將 SuppressModelStateInvalidFilter 屬性設置為 true
。 將以下突出顯示的代碼添加到 Startup.ConfigureServices
:
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
options.ClientErrorMapping[404].Link =
"https://httpstatuses.com/404";
});
綁定源參數推理
綁定源特性定義可找到操作參數值的位置。 存在以下綁定源特性:
特性 | 綁定源 |
---|---|
[[FromBody\] ] |
請求正文 |
[[FromForm\] ] |
請求正文中的表單數據 |
[[FromHeader\] ] |
請求標頭 |
[[FromQuery\] ] |
請求查詢字符串參數 |
[[FromRoute\] ] |
當前請求中的路由數據 |
[[FromServices\] ] |
作為操作參數插入的請求服務 |
如果沒有 [ApiController]
屬性或諸如 [FromQuery]
的綁定源屬性,ASP.NET Core 運行時會嘗試使用復雜對象模型綁定器。 復雜對象模型綁定器按已定義順序從值提供程序拉取數據。
在下面的示例中,[FromQuery]
特性指示 discontinuedOnly
參數值在請求 URL 的查詢字符串中提供:
[HttpGet]
public ActionResult<List<Product>> Get(
[FromQuery] bool discontinuedOnly = false)
{
List<Product> products = null;
if (discontinuedOnly)
{
products = _productsInMemoryStore.Where(p => p.IsDiscontinued).ToList();
}
else
{
products = _productsInMemoryStore;
}
return products;
}
[ApiController]
屬性將推理規則應用於操作參數的默認數據源。 借助這些規則,無需通過將屬性應用於操作參數來手動識別綁定源。 綁定源推理規則的行為如下:
[FromBody]
針對復雜類型參數進行推斷。[FromBody]
不適用於具有特殊含義的任何復雜的內置類型,如 IFormCollection 和 CancellationToken。 綁定源推理代碼將忽略這些特殊類型。[FromForm]
針對 IFormFile 和 IFormFileCollection 類型的操作參數進行推斷。 該特性不針對任何簡單類型或用戶定義類型進行推斷。[FromRoute]
針對與路由模板中的參數相匹配的任何操作參數名稱進行推斷。 當多個路由與一個操作參數匹配時,任何路由值都視為[FromRoute]
。[FromQuery]
針對任何其他操作參數進行推斷。
FromBody 推理說明
對於簡單類型(例如 string
或 int
),推斷不出 [FromBody]
。 因此,如果需要該功能,對於簡單類型,應使用 [FromBody]
屬性。
當操作擁有多個從請求正文中綁定的參數時,將會引發異常。 例如,以下所有操作方法簽名都會導致異常:
-
[FromBody]
對兩者進行推斷,因為它們是復雜類型。[HttpPost] public IActionResult Action1(Product product, Order order)
-
[FromBody]
對一個進行歸屬,對另一個進行推斷,因為它是復雜類型。[HttpPost] public IActionResult Action2(Product product, [FromBody] Order order)
-
[FromBody]
對兩者進行歸屬。[HttpPost] public IActionResult Action3([FromBody] Product product, [FromBody] Order o
禁用推理規則
若要禁用綁定源推理,請將 SuppressInferBindingSourcesForParameters 設置為 true
。在 Startup.ConfigureServices
中添加下列代碼:
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
options.ClientErrorMapping[404].Link =
"https://httpstatuses.com/404";
});
Multipart/form-data 請求推理
使用 [FromForm\]
屬性批注操作參數時,[ApiController]
屬性應用推理規則。 將推斷 multipart/form-data
請求內容類型。
要禁用默認行為,請在 Startup.ConfigureServices
中將 SuppressConsumesConstraintForFormFileParameters 屬性設置為 true
:
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
options.ClientErrorMapping[404].Link =
"https://httpstatuses.com/404";
});
錯誤狀態代碼的問題詳細信息
禁用 ProblemDetails 響應
當 SuppressMapClientErrors 屬性設置為 true
時,會禁止自動創建錯誤狀態代碼的 ProblemDetails
。 在 Startup.ConfigureServices
中添加下列代碼:
services.AddControllers()
.ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
options.ClientErrorMapping[404].Link =
"https://httpstatuses.com/404";
});
使用 [Consumes] 屬性定義支持的請求內容類型
默認情況下,操作支持所有可用的請求內容類型。 例如,如果應用配置為同時支持 JSON 和 XML 輸入格式化程序,那么操作支持多種內容類型,其中包括 application/json
和 application/xml
。
使用 [Consumes] 屬性,操作可以限制支持的請求內容類型。 將 [Consumes]
屬性應用於操作或控制器,同時指定一個或多個內容類型:
[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)
在上面的代碼中,CreateProduct
操作指定內容類型 application/xml
。 路由到此操作的請求必須指定 application/xml
的 Content-Type
頭。 如果請求未指定 application/xml
的 Content-Type
頭,會生成 415 不支持的媒體類型響應。
使用 [Consumes]
屬性,操作可以通過應用類型約束,根據傳入請求的內容類型來影響它的選擇。 請看下面的示例:
[ApiController]
[Route("api/[controller]")]
public class ConsumesController : ControllerBase
{
[HttpPost]
[Consumes("application/json")]
public IActionResult PostJson(IEnumerable<int> values) =>
Ok(new { Consumes = "application/json", Values = values });
[HttpPost]
[Consumes("application/x-www-form-urlencoded")]
public IActionResult PostForm([FromForm] IEnumerable<int> values) =>
Ok(new { Consumes = "application/x-www-form-urlencoded", Values = values });
}
在上面的代碼中,ConsumesController
配置為處理發送到 https://localhost:5001/api/Consumes
URL 的請求。 控制器的兩個操作(PostJson
和 PostForm
)都使用相同的 URL 處理 POST 請求。 如果 [Consumes]
屬性不應用類型約束,則會拋出不明確匹配異常。
[Consumes]
屬性應用於兩個操作。 PostJson
操作處理使用 application/json
的 Content-Type
頭發送的請求。 PostForm
操作處理使用 application/x-www-form-urlencoded
的 Content-Type
頭發送的請求。