【Http】一文備忘Http狀態碼(406,415,422)
最近在除錯介面時,web api 報了一個415狀態碼。好久沒見到這個狀態碼,一時還真不知道啥情況。所以,人的大腦是有遺忘規律的,為了加深印象,所以我覺得我有必要再複習一下。
1.HTTP的狀態碼
首先複習一下所有的狀態碼。
-
1xx
:屬於資訊性的狀態碼。Web API並不使用1xx的狀態碼。 -
2xx
:意味著請求執行的很成功。200
:Ok,表示請求成功;201
:Created,請求成功並建立了資源;204
:No Content,請求成功,但是不應該返回任何東西,例如刪除操作。
-
3xx
:用於跳轉。例如告訴搜素引擎,某個頁面的網址已經永久的改變了。絕大多數的Web API都不需要使用這類狀態碼。 -
4xx
:客戶端錯誤400
:Bad Request,表示API消費者傳送到伺服器的請求是有錯誤的;401
:Unauthorized,表示沒有提供授權資訊或者提供的授權資訊不正確;403
:Forbidden,表示身份認證已經成功,但是已認證的使用者卻無法訪問請求的資源;404
:Not Found,表示請求的資源不存在;405
:Method not allowed,當嘗試傳送請求到資源的時候,使用了不被支援的HTTP方法時,就會返回405狀態碼;406
:Not acceptable,這表示API消費者請求的表述格式並不被Web API所支援,並且API不會提供預設的表述格式。例如請求的媒體型別是application/xml409
:Conflict,表示請求與伺服器當前狀態衝突。通常指更新資源時發生的衝突,例如,當你編輯某個資源的時候,該資源在伺服器上又進行了更新,所以你編輯的資源版本和伺服器的不一致。當然有時候也用來表示你想要建立的資源在伺服器上已經存在了。它就是用來處理併發問題的狀態碼。415
:Unsupported media type,與406正好相反,有一些請求必須帶著資料發往伺服器,這些資料都屬於特定的媒體型別,如果API不支援該媒體型別格式,415就會被返回。422
:Unprocessable entity
-
5xx
:伺服器錯誤 -
500
:Internal server error,表示伺服器出現了錯誤,客戶端無能為力,只能以後再試試了。
——摘自楊旭老師B站視訊。
本篇重點關注狀態碼406和415,順帶看一下422。
2.”我要的你不給“——406
在http請求中,Accept表明客戶端希望接收的資料型別。當請求包含accept頭,在ASP.NET Core框架中,將會:
- 按accept頭中順序列舉媒體型別
- 嘗試找到一個能生成accept中指定的格式之一的格式化器
一旦找不到格式化器,ASP.NET Core將會:
- 返回406 Not acceptable,只要需要設定如下:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.ReturnHttpNotAcceptable = true;
})
}
- 或者嘗試找到第一個可以生成響應的格式化程式:如果ASP.NET Core沒有為所請求的格式配置格式化程式,則使用可以格式化該物件的第一個格式化程式.
如果請求沒有Accept頭:
- 使用第一個可以處理物件的格式化器來響應序列化
- 不執行任何協商,由ASP.NET Core決定返回的格式
Accept: */*,..,..
,如果Accept 包含*/*
,那麼就會忽略Accept,除非做如下配置:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers(options =>
{
options.RespectBrowserAcceptHeader = true; // false by default
});
}
這樣,在使用 API 時,與在瀏覽器中的體驗一致:
- 忽略
Accept
- 若為另行配置,將會使用JSON返回內容
3.“我給的你不要”——415
說會我們問題的初衷,報了415,我這邊ajax設定的Content-Type:application/x-www-form-urlencoded,然後asp.net core返回了415.
在HTTP中,Content-Type代表客戶端傳送的實體資料的資料型別,如果客戶端是以application/x-www-form-urlencoded ,在asp.net core中用[FromBody]接收,服務端api是不會接收資料,便會返回415 Unsupported Media Type-不支援的媒體型別。
- application/x-www-form-urlencoded,使用[FromForm]接收資料
- application/json,使用[FromBody]接收資料
4.“我給的你還不要”——422
順帶提一下並不常用,但是卻非常有用的狀態碼——422。
422
:Unprocessable entity,它是HTTP擴充套件協議的一部分。
- 伺服器已經懂得了實體的Content Type的媒體型別,也就是說415狀態碼肯定不合適;
- 此外,實體的語法也沒有問題,所以400也不合適。
但是伺服器仍然無法處理這個實體資料,這時就可以返回422。所以它通常是用來表示語意上有錯誤,或者不符合介面要求的資料,通常就表示實體驗證的錯誤。對於實體模型驗證錯誤:
ASP.NET Core預設使用的是400狀態碼-Bad Request
{
"errors": {
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 400,
"traceId": "|cb69a381-495c34b204e78961."
}
採用422會更準確的說明是實體資料問題。如果想要服務端返回422,還需要做單獨配置,詳細配置如下:
services.AddControllers(options =>
{
options.ReturnHttpNotAcceptable = true;
})
.ConfigureApiBehaviorOptions(options =>
{
options.InvalidModelStateResponseFactory = context =>
{
var problemDetails = new ValidationProblemDetails(context.ModelState)
{
Type = "https://tools.ietf.org/html/rfc7231#section-6.5.1",
Title = "One or more validation errors occurred.",
Status = StatusCodes.Status422UnprocessableEntity,
Detail = "",
Instance = context.HttpContext.Request.Path
};
problemDetails.Extensions.Add("traceId", context.HttpContext.TraceIdentifier);
return new UnprocessableEntityObjectResult(problemDetails)
{
ContentTypes = { "application/problem+json" }
};
};
});
{
"errors": {
},
"type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
"title": "One or more validation errors occurred.",
"status": 422,
"detail": "",
"instance": "/api/admin/Sms",
"traceId": "0HM25M2D86T30:00000001"
}