zoukankan      html  css  js  c++  java
  • 总结常见的违背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方法的使用场合,

    1. GET:获取资源,返回消息头和消息表示,即header和body。

    2. HEAD:获取资源元数据,返回消息头

    3. DELETE:删除资源

    4. POST:REST设计中,POST通常用来为一个已有资源创建一个从属资源(subordinate resource),如AWS S3的POST Object(或者称web post)接口。

    5. 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设计还应该遵循安全性和幂等性约束,如下:

    1. GET和HEAD应当是安全的:GET和HEAD请求不应该导致服务器状态发生改变

    2. GET、HEAD、PUT和DELETE应当是幂等的:向一个URL发送多次PUT和DELETE请求,跟只做过一次请求一样。比如PUT不能是append语义,否则不幂等。GET和HEAD也是幂等。

    统一接口原则的好处:

    1. 给一个资源URI,不用看文档就知道可以有GET、DELETE等操作及其意义,世界通用。

    2. 安全性和幂等性增加了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是这样的:

    1. 新增渠道

      POST /xhr/thirdparty/admin/channel/add.json?{渠道信息参数}
    2. 编辑渠道

    POST /xhr/thirdparty/admin/channel/update.json?{渠道信息参数}
    1. 删除渠道

    POST /xhr/thirdparty/admin/channel/delete.json?channelId=id

    这里的接口设计有三个特点:

    1. http方法都是POST;

    2. URI里携带操作信息,如URI里出现“add”,“update”,“delete”等字眼;

    3. 同一个资源由于操作不一样而URI不一样。

    其实REST式的设计中,URI即是资源的名称,也是资源的地址,因为不同的操作而资源地址不一样是不合适的。资源的操作(方法信息)应该由统一接口来表示,即http 方法PUT、POST、GET、DELETE等,而不应该放到URI中。

    对照统一接口和面向资源这两个特征来设计,上面的接口RESTful化可以是这样的:

    1. 新增渠道

    POST /xhr/thirdparty/admin/channel
    
    [渠道具体信息]
    1. 修改渠道

    PUT /xhr/thirdparty/admin/channel?channelId=id 或者PUT /xhr/thirdparty/admin/channel/${id}
    
    [渠道具体信息]
    1. 删除渠道

    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》


    相关文章:
    【推荐】 3招搞定APP注册作弊

  • 相关阅读:
    Data Base mysql备份与恢复
    java 乱码问题解决方案
    【知识强化】第二章 物理层 2.1 通信基础
    【知识强化】第二章 进程管理 2.2 处理机调度
    【知识强化】第二章 进程管理 2.1 进程与线程
    【知识强化】第一章 操作系统概述 1.3 操作系统的运行环境
    【知识强化】第一章 网络体系结构 1.1 数据结构的基本概念
    【知识强化】第一章 网络体系结构 1.2 计算机网络体系结构与参考模型
    【知识强化】第一章 网络体系结构 1.1 计算机网络概述
    【知识强化】第一章 操作系统概述 1.1 操作系统的基本概念
  • 原文地址:https://www.cnblogs.com/zyfd/p/10101253.html
Copyright © 2011-2022 走看看