本节内容,涉及到6.1-6.6(P155-182),以WebApi说明为主 。主要NuGet包:无
一、创建WebApi的最佳实践,综合了RPC和Restful两种风格的特点
1 //定义Person类和ErrorInfo类 2 public record Person(int Id, string Name, int Age); 3 public record ErrorInfo(int Code, string? Message); 4 5 6 //定义控制器和一个Get方法 7 [ApiController] 8 [Route("api/[controller]/[action]")] 9 public class TestController : ControllerBase10 {11//模拟一个persons数据集合12private List<Person> persons = new List<Person>();13public TestController()14{15var p1 = new Person(1, "ZS", 25);16var p2 = new Person(2, "LS", 18);17var p3 = new Person(3, "WU", 35);18var p4 = new Person(4, "ZL", 46);19persons.Add(p1);20persons.Add(p2);21persons.Add(p1);22persons.Add(p1);2324}2526[HttpGet("{id}")]27public ActionResult<Person> GetPersonById(int id)28{29if (id < 1)30{31return BadRequest(new ErrorInfo(1, "id必须是正数"));32}33else if(id > 4)34{35return NotFound(new ErrorInfo(2, "查无此人"));36}37else38{39return persons.FirstOrDefault(p => p.Id == id);40}41}42 }代码解读:
8行:统一设置控制器类的路径为[controller]/[action] , 控制器+方法名,前缀api可省略 。这个方式倾向于RPC风格,可以直接知道API的意图
9行:因为不需要MVC中的视图功能,所以WebApi的控制器继承ControllerBase即可,ControllerBase中定义了Response、Request、HttpContext等属性成员来获取请求和响应信息 , 以及BadRequest、NotFound、OK等方法来快速设置响应报文 。
26行:所有方法,都须加上Http方法的Attribute,主要有[HttpGet]、[HttpPost]、[HttpPut]、[HttpDelete] , 分别进行查询、新增、更新、删除操作 。这不仅有利于明确操作方法的请求类型,也有利于使用Swagger+OpenApi来生成文档 。使用Swagger时,如果没有标注 , 会报错,如果确定这个方法不生成Api,可以标注[ApiExplorerSettings(IgnoreApi = true)]
27行:返回值如果是普通类型,直接返回即可,会自动序列化为JSON格式,但如果返回值为复杂类型 , 需要使用ActionResult<T>泛型类型来包装
31,35行:使用BadRequest、NotFound、Ok等方法,快速设置响应数据,可以和ActionResult<T>很好的结合使用 。其中BadRequest的响应状态码为400 , NotFound为404,Ok为200 。同时 , 方法参加为一个自定义ErrorInfo对象,包括错误码和错误信息两个属性 , 进一步说明具体的错误信息 。方法会自动将ErrorInfo对象序列化为JSON对象
39行:直接返回对象,因为方法设置了返回值为ActionResult<T>,自动将复杂对象序列化为JSON对象 。这里严谨一点,应该判断一下是否为null
补充说明:
①HTTP的四个常用请求谓词的特征:GET/Put/DELETE是幂等操作,网关或网络请求组件会对失败请求自动重试;POST是非幂等的,需要注意重复提交的情况;GET请求的响应可以被缓存,而其它请求不能被缓存;GET和DELETE不支持请求体传参,POST和PUT支持
②HTTP的常用状态码:401,需要身份认证的但是没有提供;403 , 需要权限的但没有权限;404 , 请求的资源不存在;400,请求参数错误或其它业务错误;200,请求处理成功
③如果方法中调用了异步方法,则返回值为async Task<ActionResult<T>>
二、Api方法参数的最佳实践
1、通过URL
//通过HttpGet的参数设置请求路径,其中{}内的,为路径参数//如果方法参数的名称和{}内的不一样,则参数使用[FromRoute]指定//如果请求参数schoolName为aaa,classNo为bbb//则请求路径为api/Test/GetAll/school/aaa/class/bbb[HttpGet("school/{schoolName}/class/{classNo}")]public ActionResult<Student[]> GetAll(string schoolName, [FromRoute(Name = "classNo")] string classNum){}2、通过QueryString
//从Query中获取实参时,就不需要在HttpGet中设置路径//如果请求参数名称和方法行参名称不同 , 则要指定[FromQuery]的Name属性//假设请求参数schoolName为aaa,classNo为bbb//则请求地址为api/Test/GetAll?schoolName=aaa&classNum=bbb[HttpGet]public ActionResult<Student> GetAll(string schoolName, [FromQuery(Name = "classNo")]string classNum){}3、通过请求体
//方法参数为复杂类型时 , 自动序列化为JSON,通过请求体发送//参数中可加、可不加[FromBody]//请求地址为api/Test/AddNew[HttpPost]public ActionResult<Student> AddNew(Student studentDto){persons.Add(studentDto);return Ok(studentDto);}4、除了FromRoute、FromQuery、FromBody之外 , 还有FromForm、FromHeader等
5、传递参数最佳实践:
①GET和DELETE请求,参数使用QueryString
②POST请求 , 参数使用请求体
推荐阅读
- node.js:《接口实现文件的上传和下载》
- IQueryable和IEnumerable 快读《ASP.NET Core技术内幕与项目实战》EFCore2.5:集合查询原理揭秘
- 《饥荒》怎么玩(饥荒可以在mac上玩吗)
- 《HelloGitHub》第 79 期
- 31 《吐血整理》高级系列教程-吃透Fiddler抓包教程-Fiddler如何抓取Android系统中Flutter应用程序的包
- 《上传那些事儿之Nest与Koa》——文件格式怎么了!
- 《穿越火线》怎么改房间名字(穿越火线怎么修改房间名最新)
- 30 《吐血整理》高级系列教程-吃透Fiddler抓包教程-Fiddler如何抓取Android7.0以上的Https包-番外篇
- 山海情的原著小说_山海情是根据什么小说改编的
- 唐人街探案3剧情详解_唐人街探案3讲了什么剧情