RPC风格
面向过程RPC:
业务驱动,天然的代码风格,用控制器+操作方法的形式;把Http当成传输数据的通道,不用关心http的语义。简单直接
/Persons/GetAll:访问获得所有用户的接口
//注意:这是不符合http语义,因为把获取数据放到QueryString中而非url中
/Persons/GetById?id=8:获得id为8的用户
/Persons/Update:更新用户信息
/Persons/DeleteById/8:删除用户
/Users/AddNew:新增用户
REST风格
面向REST:按照http的语义来使用http协议,即符合http协议规范
REST是学术化的概念,仅供参考。腾讯、阿里等很多系统不RESTFUL。需要根据公司情况,进行REST的选择和裁剪
/user/888:获取编号为888的用户,符合语义(把需要定位的数据放到url中)
/Classes/5/Students:获得班级为5的学生
/user/888/orders:获取编号为888的用户所有的订单
/Schools/红星小学/Class/3/No/2/Student:红星小学三年级学号为2的学生
优点
- 通过url对资源定位,语义更清晰
- 通过http谓词表示不同的操作,接口自描述。相同的路径不同的请求谓词有不同的效果
- 如相同路径,GET谓词表获取,DELETE谓词表删除
- 可以对GET、PUT、DELETE请求进行重试。浏览器、网关会做很多事情。对于幂等操作,如果浏览器断网重连,会再次尝试发送请求
- 可以用GET请求做缓存,降低服务器压力
- 通过http状态码反映服务的的处理结果,统一错误处理结果机制
- 网关可以分析请求处理结果,进行报警
缺点
- 真实系统中额资源非常复杂,很难清晰地进行资源的划分,对技术人员的业务和技术水平要求高。如登录、请假、销假
- 不是所有的操作都能简单地对应到确定到确定的http谓词
- 系统的进化可能会改变幂等性
- 通过url进行资源定位不符合中文用户的习惯
- http状态码数量有限
- 有些环节会篡改非200响应码的响应报文,运营商、浏览器可能会向报文里面塞广告
- 有的客户端不支持PUT、DELETE请求
使用建议
1、URL:使用RPC风格:/Users/AddNew、/Persons/GetAll、/Persons/DeleteById
2、请求方式:
- 对于可以缓存的操作,使用get请求
- 对于幂等的更新操作,使用put请求
- 对于幂等的删除操作,使用delete请求
- 对于其他操作,一律使用post请求(保守、安全)
3、参数:对于保存、更新类的请求post put patch请求,把全部参数放到请求报文体中
PATCH 更新id=5 email=a@b.com age=5的用户的邮箱
写法一:/Users/5 请求体PATCH{"email":"a@b.com","age":5}
写法二:/Users 请求体PATCH{"id":5,"email":"a@b.com","age":5}
对于delete get请求,要传递的参数就是一个资源的id,因此把参数放到querystring中,尽量使用url做资源定位
删除id为5的用户
/Users/5 DELETE
/Users?id=5 DELETE
对于GET请求,一般参数的内容都不会太长,因此统一通过QueryString传递参数即可。对于极少数参数内容超过url限制的请求(如搜索),由于GET PUT请求都是幂等的,因此我们把请求改成put请求,然后通过报文体来传递参数
4、返回值:
- 对于业务错误,服务端返回合适的4xx状态码,不知道选择哪个就用400。同时,在报文体中通过code参数提供业务错误及错误消息
- 如果请求的处理成功执行,服务端返回值为200的状态码,如果有需要返回给客户的数据,则服务器把数据放到响应报文体中
具体的步骤:
1、控制器上[Route("[api/[action]]")],即代表不根据谓词匹配,优先匹配路径
2、控制器中不同的操作用不同的方法名
//向/Persons/AAA发送请求时,会根据不同的谓词调用不同的方法,但是可识别性不高,所以尽量不重名
//注:虽然会根据不同谓词调用不同方法,但签名不能相同否则不符合C#语法
[HttpGet]
AAA(int id){}
[HttpPost]
AAA(Person p){}
3、把[HttpGet] [HttpPost] [HttpDelete] [HttpPut]等添加到对于的操作方法上
注意,如果控制器中存在没有添加[HttpGet] [HttpPost]等的public方法,Swagger就会报错(但接口可以处理请求,改成private即可),可以用[ApiExplorerSettings(IgnoreApi=true)]来令此方法不显示在文档中