restful 與 webapi 詳解


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 123 Tom

自描述信息

​ 客戶端和服務端之前傳遞的每一條消息都應包含足夠的信息,這些信息不僅包含了資源的表述,也包含了資源表述的相關信息(格式和內容長度),甚至包含了資源相關的其他操作信息。

​ 超媒體作為應用程序狀態引擎(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 Create(Pet pet)
{
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 中的 UseEndpointsUseMvcUseMvcWithDefaultRoute 定義的傳統路由訪問操作。

自動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] 不適用於具有特殊含義的任何復雜的內置類型,如 IFormCollectionCancellationToken。 綁定源推理代碼將忽略這些特殊類型。
  • [FromForm] 針對 IFormFileIFormFileCollection 類型的操作參數進行推斷。 該特性不針對任何簡單類型或用戶定義類型進行推斷。
  • [FromRoute] 針對與路由模板中的參數相匹配的任何操作參數名稱進行推斷。 當多個路由與一個操作參數匹配時,任何路由值都視為 [FromRoute]
  • [FromQuery] 針對任何其他操作參數進行推斷。

FromBody 推理說明

對於簡單類型(例如 stringint),推斷不出 [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/jsonapplication/xml

使用 [Consumes] 屬性,操作可以限制支持的請求內容類型。 將 [Consumes] 屬性應用於操作或控制器,同時指定一個或多個內容類型:

[HttpPost]
[Consumes("application/xml")]
public IActionResult CreateProduct(Product product)

在上面的代碼中,CreateProduct 操作指定內容類型 application/xml。 路由到此操作的請求必須指定 application/xmlContent-Type 頭。 如果請求未指定 application/xmlContent-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 的請求。 控制器的兩個操作(PostJsonPostForm)都使用相同的 URL 處理 POST 請求。 如果 [Consumes] 屬性不應用類型約束,則會拋出不明確匹配異常。

[Consumes] 屬性應用於兩個操作。 PostJson 操作處理使用 application/jsonContent-Type 頭發送的請求。 PostForm 操作處理使用 application/x-www-form-urlencodedContent-Type 頭發送的請求。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM