最近在调试接口时,web api 报了一个415状态码。好久没见到这个状态码,一时还真不知道啥情况。所以,人的大脑是有遗忘规律的,为了加深印象,所以我觉得我有必要再复习一下。
1.HTTP的状态码
首先复习一下所有的状态码。
1xx
:属于信息性的状态码。Web API并不使用1xx的状态码。2xx
:意味着请求执行的很成功。3xx
:用于跳转。例如告诉搜素引擎,某个页面的网址已经永久的改变了。绝大多数的Web API都不需要使用这类状态码。4xx
:客户端错误406
:Not acceptable,这表示API消费者请求的表述格式并不被Web API所支持,并且API不会提供默认的表述格式。例如请求的媒体类型是application/xml,但是Web API仅支持application/json类型,并且API不会将application/json作为默认格式提供;409
:Conflict,表示请求与服务器当前状态冲突。通常指更新资源时发生的冲突,例如,当你编辑某个资源的时候,该资源在服务器上又进行了更新,所以你编辑的资源版本和服务器的不一致。当然有时候也用来表示你想要创建的资源在服务器上已经存在了。它就是用来处理并发问题的状态码。415
:Unsupported media type,与406正好相反,有一些请求必须带着数据发往服务器,这些数据都属于特定的媒体类型,如果API不支持该媒体类型格式,415就会被返回。422
:Unprocessable entity,它是HTTP扩展协议的一部分。它说明服务器已经懂得了实体的Content Type,也就是说415状态码肯定不合适;此外,实体的语法也没有问题,所以400也不合适。但是服务器仍然无法处理这个实体数据,这时就可以返回422。所以它通常是用来表示语意上有错误,通常就表示实体验证的错误。
5xx
:服务器错误
——摘自杨旭老师B站视频。
本篇重点关注状态码406和415,顺带看一下422。我们就类比爱情,对客户端与服务端交互的状态码进行解释。
2.Server:”你要的我给不了“——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;
})
}
2.1 其他策略
- 尝试找到第一个可以生成响应的格式化程序:如果
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.Server:“你给的我不要”——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.Server:“你给的,不是我想要的”——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" }
};
};
});
代码语言:javascript复制{
"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"
}