总结常见的违背Rest原则的接口设计做法
此文已由作者郑华斌授权网易云社区发布。
REST这词我们常常挂在嘴边,比如“开发一个rest接口”,又比如Spring项目的代码:
@RestControllerpublic class CommonController { @RequestMapping("/") public String index() { return "Welcome to Yanxuan DMS!";
}
CommonController使用了@RestController注解,顾名思义,告诉读者这是一个Rest接口的实现。然而以@RestController注解的接口却不一定符合Rest原则。结合最近的项目,总结下常见的违背Rest设计的一些做法。
一、一律使用POST或者GET方法
典型的错误做法:无论什么请求,一律用POST,或者‘增删改’用POST,‘查’用GET。
其实REST有个原则叫统一接口(uniform interface),统一接口原则建议了各http方法的使用场合,
GET:获取资源,返回消息头和消息表示,即header和body。
HEAD:获取资源元数据,返回消息头
DELETE:删除资源
POST:REST设计中,POST通常用来为一个已有资源创建一个从属资源(subordinate resource),如AWS S3的POST Object(或者称web post)接口。
PUT:创建或修改一个资源
PUT和POST的区别比较微妙,这里拿AWS S3(或者参考网易对象存储NOS)的接口设计来举例。其中AWS S3的详细API文档参见:http://docs.aws.amazon.com/AmazonS3/latest/API/Welcome.html。 S3有两种资源,桶(bucket)和对象(object),对象从属于某个桶。
创建一个桶的接口为:
PUT /BucketName HTTP/1.1
Host: s3.amazonaws.com
创建/修改一个对象的PUT Object接口为:
PUT /BucketName/ObjectName HTTP/1.1
Host: s3.amazonaws.com[对象数据]
AWS S3同时提供了POST Object接口,同样可以创建/修改一个对象,如下
POST /BucketName HTTP/1.1Host: s3.amazonaws.comContent-Type: multipart/form-data; boundary=9431149156168[包含对象数据的body]
获取对象的GET Object接口为:
GET /BucketName/ObjectName HTTP/1.1
Host: s3.amazonaws.com
同样的创建/修改一个对象,一个用PUT方法,另一个用POST方法,为什么?关键在于URL,PUT请求的目标URL(这里为/BucketName/ObjectName),就是将来用于获取该对象的URL,即PUT Object和GET Object的URL是一致的。但是POST Object的URL与GET ObjectURL不一样,POST 请求只知道父资源的URL(即/BucketName),表示在该父资源下创建新资源,至于新资源的确切URL,是由服务器决定的,一般来说是POST请求的响应应该包含一个Location消息头,其包含新建从属资源的URL。
安全性safe和幂等性idempotent
REST设计还应该遵循安全性和幂等性约束,如下:
GET和HEAD应当是安全的:GET和HEAD请求不应该导致服务器状态发生改变
GET、HEAD、PUT和DELETE应当是幂等的:向一个URL发送多次PUT和DELETE请求,跟只做过一次请求一样。比如PUT不能是append语义,否则不幂等。GET和HEAD也是幂等。
统一接口原则的好处:
给一个资源URI,不用看文档就知道可以有GET、DELETE等操作及其意义,世界通用。
安全性和幂等性增加了http的可靠性:如果请求没成功(但也许已成功了),只需重新发一次即可,不用担心副作用。
二、HTTP Code一律返回200
典型的错误做法:无论成功失败,HTTP Code一律返回200,具体错误信息交由json body里的内容来判断,举例如下,
某甲服务xxx接口的响应如下
HTTP/1.1 200 OK{ "status":1, //1: 成功 0: 参数异常 -1: 失败
"message":"" //返回的消息
成功时返回的数据
}
某乙服务xxx接口的响应如下
HTTP/1.1 200 OK{ "code":200, //1: 成功 0: 参数异常 -1: 失败
"msg":"" //code非200时返回的错误信息
"data":{成功时返回的数据内容}
}
其实RESTful的设计的一个标志特征是充分并正确利用HTTP响应码,典型的如:
200 -- OK,成功
301 -- Moved Permanently,重定向
400 -- Bad Request,错误的请求,比如缺少参数或者参数值不对
403 -- Forbidden,无权限访问
404 -- Not Found,url不存在
500 -- Internal Server Error,系统错误,如数据库访问失败或者bug导致的错误
设计REST接口应该遵循上面的响应码,语义明确并通用。如果像上面例子那样,任何情况都一律返回200,而具体成功与否需要到http响应消息体里去解析,而且不同的服务或开发者自定义消息体的格式,那么服务调用方就需要针对不同的服务写不同的判断逻辑,增加系统交互复杂性。
有些通用的客户端,会针对301自动处理重定向,针对500以上的响应自动重试,而一律返回200的设计是没法使用这些特性的,只能调用方一一自个处理。
三、 面向操作而不是面向资源的url设计
典型的错误做法:设计的URI是面向操作而不是面向资源的,举例如下,
某系统 设计的渠道相关的URI是这样的:
新增渠道
POST /xhr/thirdparty/admin/channel/add.json?{渠道信息参数}
编辑渠道
POST /xhr/thirdparty/admin/channel/update.json?{渠道信息参数}
删除渠道
POST /xhr/thirdparty/admin/channel/delete.json?channelId=id
这里的接口设计有三个特点:
http方法都是POST;
URI里携带操作信息,如URI里出现“add”,“update”,“delete”等字眼;
同一个资源由于操作不一样而URI不一样。
其实REST式的设计中,URI即是资源的名称,也是资源的地址,因为不同的操作而资源地址不一样是不合适的。资源的操作(方法信息)应该由统一接口来表示,即http 方法PUT、POST、GET、DELETE等,而不应该放到URI中。
对照统一接口和面向资源这两个特征来设计,上面的接口RESTful化可以是这样的:
新增渠道
POST /xhr/thirdparty/admin/channel [渠道具体信息]
修改渠道
PUT /xhr/thirdparty/admin/channel?channelId=id 或者PUT /xhr/thirdparty/admin/channel/${id} [渠道具体信息]
删除渠道
DELETE /xhr/thirdparty/admin/channel?channelId=id或者DELETE /xhr/thirdparty/admin/channel/${id}
渠道的地址为/xhr/thirdparty/admin/channel?channelId=id或者/xhr/thirdparty/admin/channel/${id},重在url唯一。
参考文献
《RESTful Web Services》
相关文章:
【推荐】 Bug是一种财富-------研发同学的错题集、测试同学的遗漏用例集
【推荐】 类文件结构与javap的使用
总结常见的违背Rest原则的接口设计做法的更多相关文章
- RESTful接口设计原则/最佳实践(学习笔记)
RESTful接口设计原则/最佳实践(学习笔记) 原文地址:http://www.vinaysahni.com/best-practices-for-a-pragmatic-restful-api 1 ...
- 设计原则:接口隔离原则(ISP)
接口隔离原则的英文是Interface Segregation Principle,缩写就是ISP.与里氏替换原则一样其定义同样有两种 定义1: Clients should not be force ...
- 优秀的API接口设计原则及方法(转)
一旦API发生变化,就可能对相关的调用者带来巨大的代价,用户需要排查所有调用的代码,需要调整所有与之相关的部分,这些工作对他们来说都是额外的.如果辛辛苦苦完成这些以后,还发现了相关的bug,那对用户的 ...
- App接口设计原则-b
1.记住密码不是真的让你记住密码,这里仅仅指的是一种自动登录的手段.不管在任何地方,明文存储的密码都是安全隐患,是必须尽量避免的.你可以采用某种方式对用户名.密码以及时间戳(重要)进行签名,再次登录时 ...
- 微信小程序的Web API接口设计及常见接口实现
微信小程序给我们提供了一个很好的开发平台,可以用于展现各种数据和实现丰富的功能,通过小程序的请求Web API 平台获取JSON数据后,可以在小程序界面上进行数据的动态展示.在数据的关键 一环中,我们 ...
- RESTful接口设计原则和优点
RESTful架构优点: 前后端分离,减少流量 安全问题集中在接口上,由于接受json格式,防止了注入型等安全问题 前端无关化,后端只负责数据处理,前端表现方式可以是任何前端语言(android,io ...
- IOS设计模式的六大设计原则之接口隔离原则(ISP,Interface Segregation Principle)
定义 客户端不应该依赖它不需要的接口: 一个类对另一个类的依赖应该建立在最小的接口上. 定义解读 定义包含三层含义: 一个类对另一个类的依赖应该建立在最小的接口上: 一个接口代表一个角色,不应该将不同 ...
- 面向对象的六大原则之 接口隔离原则——ISP
ISP = Interface Segregation Principle ISP的定义如下: 1.客户端不应该依赖他不需要的接口 2.一个类对另外一个类的依赖性应该是建立在最小的接口上 3.不应 ...
- atitit.基于http json api 接口设计 最佳实践 总结o7
atitit.基于http json api 接口设计 最佳实践 总结o7 1. 需求:::服务器and android 端接口通讯 2 2. 接口开发的要点 2 2.1. 普通参数 meth,p ...
随机推荐
- 「小程序JAVA实战」小程序的分享和下载功能(69)
转自:https://idig8.com/2018/09/25/xiaochengxujavashizhanxiaochengxudefenxianghexiazaigongneng68/ 在小程序上 ...
- 决策树与树集成模型(bootstrap, 决策树(信息熵,信息增益, 信息增益率, 基尼系数),回归树, Bagging, 随机森林, Boosting, Adaboost, GBDT, XGboost)
1.bootstrap 在原始数据的范围内作有放回的再抽样M个, 样本容量仍为n,原始数据中每个观察单位每次被抽到的概率相等, 为1/n , 所得样本称为Bootstrap样本.于是可得到参数θ的 ...
- Mysql 性能分析 Explain
Mysql Query Optmize: 查询优化器, SQL语句会给Query Optimize他会执行他认为最优的方式.. Mysql 常见问题 CPU饱和,IO磁盘发生在装入数据大于内存时. E ...
- docker redis
https://www.cnblogs.com/cgpei/p/7151612.html 重启docker >systmctl restart docker >mkdir -p ~/red ...
- 几组不错的X264自定义编码<转>
转帖地址:http://tieba.baidu.com/p/4201033507 一般直播时使用A设定即可.你尝试设置并找出你最满意的设定 A为最需最低CPU资源,E为最高. A8x8dct=1 aq ...
- windows到ubuntu
按照xmarks同步浏览器书签. mvn, copy setting.xml 最好不要用apt-get install maven, 占用/的磁盘空间 mvn -U package -P"d ...
- 【324】Python 库说明(安装&卸载)
参考:Python_安装官方whl包和tar.gz包 参考:Unofficial Windows Binaries for Python Extension Packages 参考:PyPI 参考:直 ...
- JavaScript中call,apply,bind方法
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- NBU 还原主/others服务器的SQLSERVER
一.将数据库还原回主服务器 1.运行NetBackup MS SQL Client(10.10.0.14 administrator)2.设置连接属性 testsa 添加验证凭据 3.选择恢复,再选择 ...
- 关于scanf的算法(位操作)
题目要求:输入有12行数据,每一行分别是每个月的余额.计算他们的平均值后输出.在输出时要在前面加上“$”,并在四舍五入后保留小数点后两位. 方法1: float a,b; main() { ;) b+ ...