ASP.NETCore如何返回错误码
REST:通过HTTP状态码返回服务器端的处理结果
问题
- HTTP状态码数量有限
- HTTP的状态码并不适合用来表示业务层面的错误码,它是一个用来表示技术层面的信息的状态码。新增用户的操作中,如果服务器端要求JSON格式,客户端提交XML,服务器返回400是没问题的。但是如果用户名格式错误或者用户名重复,存在200派和400派
400派观点
- 网关等可以监控HTTP状态码,如果接口频繁出现4xx状态码,那么就说明客户端的代码不完善
- 很多的系统都是按照HTTP状态码的不同含义进行设计的。如果失败了服务器返回的状态码还是200的话,这会违背软件设计的初衷
200派观点
网络的问题归网络、业务的问题归业务。业务错误不应该和技术错误混在一起。把系统日志和业务日志区分开
大企业也不统一
百度:200派
谷歌:400派
同一家公司:
企业微信和微信小程序:200派
微信支付:400派
建议400派
1、对于数据库服务器连接失败、请求报文格式、服务器端异常等业务错误,服务器端应该返回4xx、5xx等状态码
2、对于业务层面的错误,比如用户不存在,我们要使用4xx等HTTP状态码返回。同样在响应报文体给出详细的错误信息,比如{”code“:3,"message":"用户不存在"}。
3、不仅要返回4xx的HTTP状态码,而且不要忘了通过响应报文体给出详细的错误信息。对于用户不存在,不仅要404,而且把响应报文体设置为{“code”:3,”message”:”用户名已存在”},这样能区分出来哪里的问题
ASP.NET Core中Rest使用建议
- 使用RPC风格:Users/AddNew、Users/GetAll、Users/DeleteById
- 对于可以缓存的操作,使用Get请求;对于幂等的更新操作,使用PUT请求;对于幂等的删除操作,使用DELETE请求;对于其他操作,统一使用POST请求
- 参数:保存、更新类的请求使用POST、PUT请求,把全部参数都放到请求报文体中;对于GET和DELETE请求,把参数放到QueryString中。推荐尽量使用URL做资源定位
- 对于业务错误,服务器端返回合适的4XX状态码,不知道选择哪个状态码就用400;同时,在报文体中通过code参数提供业务错误码以及错误信息。
- 如果请求的处理执行成功,服务器端返回为200的HTTP状态码,如果有需要返回给客户端数据的,则服务器端把这些数据放到响应报文体中
实现技术
- 控制器上[Route("[controller]/[action]")]
- 强制要求控制器中不同的操作用不同的方法名
- 把[HttpGet]、[HttpPost]、[HttpDelete]、[HttpPut]等添加到对应的操作方法上 注意:如果控制器中存在一个没有添加[HttpGet]、[HttpPost]等的public方法,Swagger就会报错,可以用[ApiExplorerSettings(IgnoreApi=true)]
ASP.NET Core Web API控制器及返回值
控制器类
1、ControllerBase与Controller
Controller继承自ControllerBase,Controller在ControllerBase基础上又提出了一些新方法,比如View,Json
2、控制器类可以不显式地继承自任何类
比如新建一个Controller
[ApiController]
[Route("[controller]/[action])"]
public class HelloController
{
[HttpGet]
public int Add(int i,int j)
{
return i+j;
}
}
好处:继承层次的越多,单元测试越麻烦,这样不继承任何类的Controller类,单元测试更加方便,
坏处:ControllerBase里面的方法调用不了。
Action方法的异步
1、Action方法既可以同步也可以异步
2、异步Action方法的名字一般不需要以Async结尾,以Async结尾是习惯,而不是必须的。
3、Web API中Action方法的返回值如果是普通数据类型,那么返回值就会默认被序列化为Json格式
4、Web API中Action方法的返回值同样支持IActionResult类型,不包含类型信息,因此Swagger等无法推断出类型,所以推荐用ActionResult<T>,它支持类型转换,从而用起来更简单
public ActionResult<Person> GetPerson(int id)
{
if (id <= 0)
return BadRequest("id必须是正数");
else if (id == 1)
return new Person(1, "杨中科", 18);
else if (id == 2)
return new Person(2, "Zack", 8);
else
return NotFound(“人员不存在”);//自定义消息也重要
}
ASP.NET Core Web API 的参数问题
捕获URL占位符
1、在[HttpGet]、[HttpPost]等中使用占位符,比如{schoolName},捕捉路径中的内容,从而供Action方法的参数使用 Action方法的参数使用。
// /Students/GetAll/school/MIT/class/A001
[HttpGet("school/{schoolName}/class/{classNo}")]
2、捕获的值会被自动赋值给Action中的同名的参数;如果名字不一致,可以用
[FromRoute(Name="名字")]
捕获QueryString的值
- 使用[FromQuery]来获取QueryString中的值。如果名字一致,只要为参数添加[FromQuery]即可;而如果名字不一致,[FromQuery(Name=名字)]。
- QueryString和Route可以混用
Json报文体
Web API的开发模式下,Json格式的请求体是主流。
只要声明一个模型类和Json请求的格式一致即可
也是可以把从URL获取参数、从请求报文体获取数据等这些混合使用
[HttpPost("classId/{classId}")]
public ActionResult<long> AddNew(long classId,StudentModel s)
一定要设定请求头中的Content-Type为application/json,而且数据必须是合法的json格式