• Restful API 架构与设计参考原则


    1. 什么是REST
    REST全称是Representational State Transfer,中文意思是表述(编者注:通常译为表征)性状态转移。 它首次出现在2000年Roy Fielding的博士论文中,Roy Fielding是HTTP规范的主要编写者之一。 他在论文中提到:"我这篇文章的写作目的,就是想在符合架构原理的前提下,理解和评估以网络为基础的应用软件的架构设计,得到一个功能强、性能好、适宜通信的架构。REST指的是一组架构约束条件和原则。" 如果一个架构符合REST的约束条件和原则,我们就称它为RESTful架构。

    REST本身并没有创造新的技术、组件或服务,而隐藏在RESTful背后的理念就是使用Web的现有特征和能力, 更好地使用现有Web标准中的一些准则和约束。虽然REST本身受Web技术的影响很深, 但是理论上REST架构风格并不是绑定在HTTP上,只不过目前HTTP是唯一与REST相关的实例。 所以我们这里描述的REST也是通过HTTP实现的REST。

    什么是RESTful架构:

    每一个URI代表一种资源;
    客户端和服务器之间,传递这种资源的某种表现层;
    客户端通过四个HTTP动词(GET/POST/PUT/DELETE),对服务器端资源进行操作,实现”表现层状态转化”。
     

    URI
    要让一个资源可以被识别,需要有个唯一标识,在Web中这个唯一标识就是URI(Uniform Resource Identifier)。 URI既可以看成是资源的地址,也可以看成是资源的名称。如果某些信息没有使用URI来表示,那它就不能算是一个资源, 只能算是资源的一些信息而已。URI的设计应该遵循可寻址性原则,具有自描述性,需要在形式上给人以直觉上的关联。

     
    HTTP动词
     

    1. 使用GET、POST、PUT、DELETE这几种请求模式
    请求模式也可以说是动作、数据传输方式,通常我们在web中的form有GET、POST两种,而在HTTP中,存在下发这几种。

    GET (选择):从服务器上获取一个具体的资源或者一个资源列表。 
    POST (创建): 在服务器上创建一个新的资源。
    PUT(更新):以整体的方式更新服务器上的一个资源。 
    PATCH (更新):只更新服务器上一个资源的一个属性。
    DELETE(删除):删除服务器上的一个资源。

    1.1 使用名词而不是动词
    Resource
    资源

    GET
    读 POST
    创建 PUT
    修改 DELETE
    /cars 返回 cars集合 创建新的资源 批量更新cars 删除所有cars
    /cars/711 返回特定的car 该方法不允许(405) 更新一个指定的资源 擅长指定资源
    不要使用:

    /getAllCars
    /createNewCar
    /deleteAllRedCars

    1.2 Get方法和查询参数不应该涉及状态改变
    使用PUT, POST 和DELETE 方法 而不是 GET 方法来改变状态,不要使用GET 进行状态改变:

    GET /users/711?activate 
    GET /users/711/activate

     1.3 使用复数名词
    不要混淆名词单数和复数,为了保持简单,只对所有资源使用复数。

    /cars 而不是 /car
    /users 而不是 /user
    /products 而不是 /product
    /settings 而部署 /setting

     1.4 使用子资源表达关系
    如果一个资源与另外一个资源有关系,使用子资源:

    GET /cars/711/drivers/ 返回 car 711的所有司机
    GET /cars/711/drivers/4 返回 car 711的4号司机

    2. 为集合提供过滤 排序 选择和分页等功能
    比如在数据过多, 需要对数据进行分页请求的时候, 我们应该统一 API 请求参数. 常见的有这些.

    limit=10 指定返回记录的数量
    offset=10 指定返回记录的开始位置。
    page=2&per_page=100 指定第几页,以及每页的记录数。
    sortby=name&order=asc 指定返回结果按照哪个属性排序,以及排序顺序。
    animal_type_id=1 指定筛选条件
    Filtering过滤:

    使用唯一的查询参数进行过滤:

    GET /cars?color=red 返回红色的cars
    GET /cars?seats<=2 返回小于两座位的cars集合

    Sorting排序:

    允许针对多个字段排序

    GET /cars?sort=-manufactorer,+model

    这是返回根据生产者降序和模型升序排列的car集合

    Field selection

    移动端能够显示其中一些字段,它们其实不需要一个资源的所有字段,给API消费者一个选择字段的能力,这会降低网络流量,提高API可用性。

    GET /cars?fields=manufacturer,model,id,color

    Paging分页

    使用 limit 和offset.实现分页,缺省limit=20 和offset=0;

    GET /cars?offset=10&limit=5

    为了将总数发给客户端,使用订制的HTTP头: X-Total-Count.

    链接到下一页或上一页可以在HTTP头的link规定,遵循Link规定:

    Link: <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=15&limit=5>; rel="next",
    <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=50&limit=3>; rel="last",
    <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=0&limit=5>; rel="first",
    <https://blog.mwaysolutions.com/sample/api/v1/cars?offset=5&limit=5>; rel="prev",

    3. 版本化你的API
    API的开发直接关系了APP是否可以正常使用,如果原本运行正常的API,突然改动,那么之前使用这个API的APP可能无法正常运行。APP是不可能强迫用户主动升级的,因此,通过API版本来解决这个问题。也就是说,API的多个版本是同时运行的,而且都要保证可以正常使用。

    按照RESTful的规范,不同的版本也应该用相同的API URL,通过header信息来判断版本,再调用不同版本的程序进行处理。但是这明显会给开发带来巨大的成本。使得API版本变得强制性,不要发布无版本的API,使用简单数字,避免小数点如2.5.

    域名

    应该尽量将API部署在专用域名之下,如:https://api.example.com

    也可以放在主域名下:https://example.org/api/

    版本

    不同的版本,用不同的URL来提供服务,在URL中通过v1、v2来区分版本号,比如v2.api.xxx.com/user的方式,或者http://api.domain.com/v2  或者http://www.domain.com/api/v2 。

    放入到头信息的Accept中
    制定版本并在版本之间平缓过渡对于设计和维护一套API是个巨大的挑战。所以,最好在设计之初就使用一些方法来预防可能会遇到的问题。
    为了避免API的变动导致用户使用中产生意外结果或调用失败,最好强制要求所有访问都需要指定版本号。请避免提供默认版本号,一旦提供,日后想要修改它会相当困难。
    最适合放置版本号的位置URL中,或者是头信息(HTTP Headers)中在 Accept 段中使用自定义类型(content type)与其他元数据(metadata)一起提交。

    https://api.example.com/v1/

    Accept: application/vnd.heroku+json; version=3
    提供 Request-Id

    为每一个请求响应包含一个Request-Id字段,并使用UUID作为该值。通过在客户端、服务器或任何支持服务上记录该值,它能主我们提供一种机制来跟踪、诊断和调试请求。

    4 .json数据类型
    Number:整数或浮点数
    String:字符串
    Boolean:true 或 false
    Array:数组包含在方括号[]中
    Object:对象包含在大括号{}中
    Null:空类型
    所以,传输的数据类型不能超过这六种数据类型。以前,我们曾经试过传输Date类型,它会转为类似于"2016年1月7日 09时17分42秒 GMT+08:00"这样的字符串,这在转换时会产生问题,不同的解析库解析方式可能不同,有的可能会转乱,有的可能直接异常了。要避免出错,必须做特殊处理,自己手动去做解析。为了根除这种问题,最好的解决方案是用毫秒数或者字符串表示日期。

    使用详细的错误包装错误:

    {

    "errors": [

    {

    "userMessage": "Sorry, the requested resource does not exist",

    "internalMessage": "No car found in the database",

    "code": 34,

    "more info": "http://dev.mwaysolutions.com/blog/api/v1/errors/12345"

    }

    ]

    }
     

    返回的数据结构

    {
    code:0,
    message: "success",
    data: { key1: value1, key2: value2, ... }
    }
     

    code: 返回码,0表示成功,非0表示各种不同的错误
    message: 描述信息,成功时为"success",错误时则是错误信息
    data: 成功时返回的数据,类型为对象或数组
     

    data字段只在请求成功时才会有数据返回的。数据类型限定为对象或数组,当请求需要的数据为单个对象时则传回对象,当请求需要的数据是列表时,则为某个对象的数组。这里需要注意的就是,不要将data传入字符串或数字,即使请求需要的数据只有一个,比如token,那返回的data应该为:

    // 正确 data: { token: abcdedf }

    9. 使用Http状态码处理错误
    不同错误需要定义不同的返回码,属于客户端的错误和服务端的错误也要区分,比如1XX表示客户端的错误,2XX表示服务端的错误

    如果你的API没有错误处理是很难的,只是返回500和出错堆栈不一定有用

    Http状态码提供70个出错,我们只要使用10个左右:

    200 OK - [GET]:服务器成功返回用户请求的数据,该操作是幂等的(Idempotent)。
    201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。
    202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务)
    204 NO CONTENT - [DELETE]:用户删除数据成功。
    400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操作,该操作是幂等的。
    401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。
    403 Forbidden - [*] 表示用户得到授权(与401错误相对),但是访问是被禁止的。
    404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操作,该操作是幂等的。
    406 Not Acceptable - [GET]:用户请求的格式不可得(比如用户请求JSON格式,但是只有XML格式)。
    410 Gone -[GET]:用户请求的资源被永久删除,且不会再得到的。
    422 Unprocesable entity - [POST/PUT/PATCH] 当创建一个对象时,发生一个验证错误。
    500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
     

    10.允许覆盖http方法
    一些代理只支持POST 和 GET方法, 为了使用这些有限方法支持RESTful API,需要一种办法覆盖http原来的方法。

    使用订制的HTTP头 X-HTTP-Method-Override 来覆盖POST 方法.

    参考:

    https://segmentfault.com/a/1190000008697972#articleHeader3
    http://blog.csdn.net/jasonhui512/article/details/53141390
    http://www.cnblogs.com/kuyuecs/p/5949075.html
    http://mclspace.com/2015/11/03/restful-note/
    ---------------------
    作者:曾先森向前进
    来源:CSDN
    原文:https://blog.csdn.net/zwqjoy/article/details/78788915
    版权声明:本文为博主原创文章,转载请附上博文链接!

  • 相关阅读:
    bugKu getshell
    XCTF 进阶区 CAT
    php弱类型比较
    XCTF command_execution
    关于错误 openssl/ssl.h:没有那个文件或目录的解决办法
    libffi-dev : 依赖: libffi6 (= 3.2.1-4) 但是 3.2.1-4kord 正要被安装
    如何查看 Ubuntu下已安装包版本号
    git 下载指定tag版本的源码
    ubuntu 环境 openstack 源码包制成 deb 包
    fedora 国内源
  • 原文地址:https://www.cnblogs.com/GarfieldEr007/p/10140900.html
Copyright © 2020-2023  润新知