目录
一、Web API项目创建入门
浏览器和服务器之间传递的主要是HTML,而手机App等客户端和服务端之间传递的是JSON等结构化的数据。我们把提供结构化数据服务的接口叫做Web API。
1.1 Web API 项目的创建
创建成功后:
项目中生成的样本代码 WeatherForecastController.cs是一个控制类,基本结构如下:
//这个路由控制规则设置对 /WeatherForecast路径请求由WeatherForecastController来处理。
[ApiController] //Web API控制类添加的Attribute
//设置路由规则
[Route("[controller]")] // [controller]代表控制器名字,也就是WeatherForecast
public class WeatherForecastController : ControllerBase
{
[HttpGet] //作为操作方法的入口,因此下面方法名是什么都不影响程序
public IEnumerable<WeatherForecast> Get() //处理 /WeatherForecast的请求
{
//代码块
}
}
总结:控制器类上添加的[Route("[controller]")]以及Get方法上添加的[HttpGet]决定了当客户端向 /WeatherForecast这个路径发送GET请求的时候,又Get方法进行处理。Get方法返回的对象会被自动进行的JSON序列返回给客户端。
项目启动后显示界面:
这个界面是我们创建项目的时候勾选的【启用OpenAPI支持】所启用的Swagger页面,这个界面会根据项目中的接口定义生成一个接口定义浏览的界面。
1.2 Post、Put等操作方法
Web API会根据HTTP请求的谓词来匹配操作方法,因此我们可以为控制器类增加一个[httpPost]和[HttpPut]等处理POST和PUT请求。
例 在WeatherForecastController中增加一个SaveNote方法:
运行后发现在Swagger页面中多出了一个Post请求选项。点击【POST】,再点击右上角的【Try it out】按钮,出现了默认JSON格式的请求报文模板:
二、Restful
2.1 什么是REST?
Web API开发有两种风格:
1.面向过程的 (简称RPC)
2.面向REST的(简称REST)
在RPC风格的Web API中,通过“控制器/操作方法”的形式把服务器端的代码当做方法去调用。把HTTP当成传输数据的通道,不关心HTTP谓词。通过QueryString(查询字符串)、请求报文体给服务器传递数据或者状态码::
- 当需要加载所有用户的时候,我们就向/Persons/GetAll这个路径发送GET请求.
- 当需要加载id=8的用户的时候就向/Persons/GetById?id=8这个路径发送GET请求.
- 当需要更新id=8的用户的时候就向/Persons/Update这个路径发送POST请求
那什么是REST:按照HTTP的语义来使用HTTP协议:
- 使用URL进行资源定位。获取id=8:/user/8;获取id=8的用户的订单列表:/user/8/orders.
- HTTP谓词:GET(获取资源)、POST(新增资源)、PUT(整体更新,不存在则创建),DELETE(删除资源).
- DELETE、PUT、GET是幂等的,POST是不幂等的;
何为幂等?
幂等就是对于一个接口采用同样的参数请求一次和请求多次的结果是一致的,不会因为多次请求而产生副作用。(比如一个人发表评论的时候由于网卡又点击了一次发布,最终数据库只保存了一次的发布内容就是幂等)
- GET的响应可以被缓存;
- 服务端通过状态码反映资源获取的结果:404(访问用户不存在),403(没有权限),201(新增用户请求成功);
那么如何请求Restful风格的控制器呢?
/*
1.当我们需要加载所有用户的时候就向/api/Persons这个路径发生GET请求,添加了
[HttpGet]的GetPersons方法就会被调用
2.当我们需要加载id=8的用户的时候,向/api/Person/8这个路径发送GET请求,添加
了[HttpGet("{id}")]的方法就会被调用
......................
......................
*/
[Route("api/[controller]")]
public class PersonController : ControllerBase
{
[HttpGet]
public IEnumerable<Person> GetPerson();
[HttpGet("{id}")]
public Person GetPerson(long id);
[HttpPut("{id}")]
public void UpdatePerson(long id,Person person)
[HttpPost("{id}")]
public void SavePerson(Person person);
[HttpDelete("{id}")]
public void DeletePerson(long id);
}
2.2 Restful 的优缺点
优点:
- 通过URL进行定位,避免使用QueryString,报文体定位,语义更清晰
- 通过HTTP谓词表示不同的操作,接口统一且具有自描述性
- 可以对GET、PUT、DELETE等幂等操作失败后进行重试
- 可以对GET请求进行缓存,提升系统的访问速度,降低服务器压力
- 通过HTTP状态码反映服务端的处理结果,能够统一错误码
- 网管系统可以根据状态码来分析系统的访问数据
缺点:
- 真实系统中的资源非常复杂,很难清晰的进行资源划分
- 不是所有的操作都能够简单的对应到确定的HTTP谓词中
- 系统进化可能改变幂等性
- HTTP状态码个数有限,无法满足
- 有些客户端可能不支持PUT、DELETE请求
三、Web API简单实例
3.1 开发Web API
(1)创建一个控制器类:
[Route("api/[controller]/[action]")]
[ApiController]
public class LoginController : ControllerBase
{
[HttpPost]
public ActionResult<LoginResult> Login(LoginRequest loginReq)
{
if(loginReq.UserName=="admin" && loginReq.Password=="123456")
{
var processes = Process.GetProcesses().Select(p => new ProcessInfo(
p.Id,p.ProcessName,p.WorkingSet)).ToArray();
return new LoginResult(true, processes);
}
else
{
return new LoginResult(false, null);
}
}
}
//请求的参数信息
public record LoginRequest(string UserName,string Password);
//进程信息,分别表示: 进程ID 进程名 进程分配的物理内存量
public record ProcessInfo (int Id,string ProcessName, long WorkingSet);
//请求信息是否正确
public record LoginResult(bool IsOK, ProcessInfo[] Processes);
在Swagger页面测试Login方法:
当我们通过请求报文体设置错误的用户信息时:
当设置正确的信息时: