资讯专栏INFORMATION COLUMN

总结常见的违背Rest原则的接口设计做法

X1nFLY / 1555人阅读

摘要:此文已由作者郑华斌授权网易云社区发布。结合最近的项目,总结下常见的违背设计的一些做法。其实有个原则叫统一接口,统一接口原则建议了各方法的使用场合,获取资源,返回消息头和消息表示,即和。参考文献文章来源网易云社区

此文已由作者郑华斌授权网易云社区发布。

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/Am...。 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》

文章来源: 网易云社区

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/25333.html

相关文章

  • 设计模式系列(总纲)

    摘要:前言关于设计模式,想必大家的第一感觉就是过于高深,有点虚吧。为什么要学习设计模式因为要装逼啊咳咳,大家请忽略前面那句话。处处都是设计模式的体现,所以若想攻下,设计模式是必学的。下节预告单例模式 前言 关于设计模式,想必大家的第一感觉就是过于高深,有点虚吧。相对来说,我们还是更熟悉ssh或者ssm之类的开发框架,一个工具用久了就会熟能生巧,就像刷漆工,时间长了也知道如何刷的一手漂亮的好墙...

    leiyi 评论0 收藏0
  • REST API设计理念与 Python Mixin模式

    摘要:飞机就是一种交通工具,可飞行的能力是是飞机的属性,通过继承接口来获取语言可没有接口功能,但是它可以多重继承。说是,因为从语法上看,的确是通过多重继承实现的。所以从含义上理解,只是一个,不是一个。比如飞机照样可以载客,就是不能飞了 REST API设计理念 showImg(https://segmentfault.com/img/remote/1460000019923606);sho...

    waruqi 评论0 收藏0
  • REST API设计理念与 Python Mixin模式

    摘要:飞机就是一种交通工具,可飞行的能力是是飞机的属性,通过继承接口来获取语言可没有接口功能,但是它可以多重继承。说是,因为从语法上看,的确是通过多重继承实现的。所以从含义上理解,只是一个,不是一个。比如飞机照样可以载客,就是不能飞了 REST API设计理念 showImg(https://segmentfault.com/img/remote/1460000019923606);sho...

    iflove 评论0 收藏0
  • JavaScript 设计模式系列 - 策略模式与动态表单验证

    摘要:策略模式又称政策模式,其定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。的表单具有表单验证功能,用来校验用户输入的表单内容。实际需求中表单验证项一般会比较复杂,所以需要给每个表单项增加自定义校验方法。 showImg(https://segmentfault.com/img/remote/1460000020135990); 策略模式 (Strategy Pattern...

    宋华 评论0 收藏0
  • 如何快速搭建一个微服务架构

    摘要:如何快速搭建一个微服务架构上图异步通信方式通常异步的生产者消费者模式,通过等异步消息通讯协议规范。数据的去中心化,进一步降低了微服务之间的耦合度,不同服务可以采用不同的数据库技术等。 什么是微服务? 微服务(Microservices Architecture)是一种架构风格,一个大型复杂软件应用由一个或多个微服务组成。系统中的各个微服务可被独立部署,各个微服务之间是松耦合的。每个微服...

    MockingBird 评论0 收藏0

发表评论

0条评论

X1nFLY

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<