• RESTful


    一. REST是什么

    通过一个HTTP请求(GET, POST, PUT and DELETE)来对信息进行CRUD的一种方式。相比诸如SOAP和RPC之类的方法更简单。

    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。

    StackOverflow上的一段描述很有意思:
    A 'REST API' is almost always just an 'HTTP API' given a different (wrong) name to make it sound better.
    Twitter和Amazon Simple Storage Service公开对外的接口就是REST的。

    RESTRepresentational State Transfer)只是为分布式超媒体系统设计的一种架构风格,而不是标准。基于Web的架构实际上就是各种规范的集合,这些规范共同组成了Web架构,比如HTTPCS模式都是规范。每当我们在原有规范的基础上增加新的规范时,就会形成新的架构。而REST正是这样一种架构,它结合了一系列规范,形成了一种新的基于Web的架构风格。

    传统的web应用大多是BS架构,涉及如下规范:1)客户-服务器;2)无状态性;3)缓存。REST在BS架构基础上增加了三个新规范:统一接口、分层系统和按需代码。

    1)统一接口:REST架构风格的核心特征就是强调组件之间有一个统一的接口,表现为再REST世界里,网络上的所有事物都被抽象为资源,REST通过通用的连接器接口对资源进行操作。这样设计的好处是保证系统提供的服务都是解耦的,极大地简化了系统,从而改善了系统的交互性和可重用性。

    2)分层系统:分层系统规则的加入提高了各种层次之间的独立性,为整个系统的复杂性设置了边界,通过封装遗留的服务,使新的服务器免受遗留客户端的影响,提高了系统的可伸缩性。

    3)按需代码:REST允许对客户端功能进行扩展。比如,通过下载并执行applet或脚本形式的代码来扩展客户端的功能。但这在改善系统可扩展性的同时降低了可见性,所以只是REST的一个可选约束。

    REST架构是针对Web应用而设计的,目的是为了降低开发的复杂性,提供系统的可伸缩性。REST提出如下设计准则

    1)网络上所有事物都被抽象为资源(resource)。

    2)每个资源对应一个唯一的资源标识符(Resource identifier)。

    3)通过通用的连接器接口对资源进行操作。

    4)对资源的各种操作不会改变资源标识符。

    5)所有的操作都是无状态的。

    REST是基于HTTP的,所有对资源的操作行为都通过HTTP实现。HTTP把对一个资源的操作限制在4种方法内:GETPOSTPUTDELETE

    REST之所以可以提高系统的可伸缩性,就是因为它要求所有操作都是无状态的。由于没有上下文的约束,做分布式和集群时更简单,也可以有效地利用缓冲池(Pool),并且由于服务器端不需要记录客户端的一系列访问,也就减少了服务器端的性能损耗。

    二. REST测试

    浏览器插件

    如果是GET请求,测试起来非常简单:只需要在浏览器地址栏里拼就可以了
    比如:
    GET /blog/?name1=value1&name2=value2 HTTP/1.1
    Host: carsonified.com

    但对于POST(以及DELETE和PUT)请求,测试起来没那么直接,需要放到HTTP Message Body里。
    比如:
    POST /blog/ HTTP/1.1
    Host: carsonified.com
    name1=value1&name2=value2

    所以就有了一些浏览器插件作为辅助。

    对于Firefox,有一个叫REST Client的(https://addons.mozilla.org/zh-cn/firefox/addon/restclient/)。

    对于Chrome,是叫Advanced REST Client(https://chrome.google.com/webstore/detail/advanced-rest-client/hgmloofddffdnphfgcellkdfbfbjeloo/reviews)。直接在Chrome Store里下载就行。建议挂VPN装。因为装完后会从某个blogspot下载个更新,如果没挂VPN的话会被墙,没法更新。

    Postman

    postman支持5中body:none,form-data,x-www-form-urlencoded,raw,binary。

    form-data: 就是http请求中的multipart/form-data,它会将表单的数据处理为一条消息,以标签为单元,用分隔符分开。既可以上传键值对,也可以上传文件。当上传的字段是文件时,会有Content-Type来表名文件类型;content-disposition,用来说明字段的一些信息.由于有boundary隔离,所以multipart/form-data既可以上传文件,也可以上传键值对。

     

    form-data格式下不要设置headers,应用会自适应。

    You shouldNEVERset that header yourself. We set the header properly with the boundary. If you set that header, we won't and your server won't know what boundary to expect

    (since it is added to the header). Remove your custom Content-Type header and you'll be fine.

    x-www-form-urlencoded就是application/x-www-from-urlencoded,会将表单内的数据转换为键值对,比如,name=java&age = 23

     raw:可以上传任意格式的文本,可以上传text、json、xml、html等

    binary:相当于Content-Type:application/octet-stream,从字面意思得知,只可以上传二进制数据,通常用来上传文件,由于没有键值,所以,一次只能上传一个文件。

    备注:multipart/form-data与x-www-form-urlencoded区别

    multipart/form-data:既可以上传文件等二进制数据,也可以上传表单键值对,只是最后会转化为一条信息。

     x-www-form-urlencoded:只能上传键值对,并且键值对都是间隔分开的。

    三. REST API设计

    参考阮一峰的《RESTful API 设计指南》,一个样例《RESTful API 设计指南 —— 最佳实践》

    1.协议

    API与用户的通信协议,总是使用HTTPs协议。

    2.域名

    应该尽量将API部署在专用域名之下。
    https://api.example.com
    如果确定API很简单,不会有进一步扩展,可以考虑放在主域名下。
    https://example.org/api/

    3.版本(Versioning)

    应该将API的版本号放入URL。
    https://api.example.com/v1/
    另一种做法是,将版本号放在HTTP头信息中,但不如放入URL方便和直观。Github采用这种做法。

    4.路径(Endpoint)

    路径又称"终点"(endpoint),表示API的具体网址。
    在RESTful架构中,每个网址代表一种资源(resource),所以网址中不能有动词,只能有名词,而且所用的名词往往与数据库的表格名对应。一般来说,数据库中的表都是同种记录的"集合"(collection),所以API中的名词也应该使用复数。
    举例来说,有一个API提供动物园(zoo)的信息,还包括各种动物和雇员的信息,则它的路径应该设计成下面这样。
    https://api.example.com/v1/zoos
    https://api.example.com/v1/animals
    https://api.example.com/v1/employees

    5.HTTP动词

    对于资源的具体操作类型,由HTTP动词表示。
    常用的HTTP动词有下面五个(括号里是对应的SQL命令)。
     GET(SELECT):从服务器取出资源(一项或多项)。
     POST(CREATE):在服务器新建一个资源。
     PUT(UPDATE):在服务器更新资源(客户端提供改变后的完整资源)。
     PATCH(UPDATE):在服务器更新资源(客户端提供改变的属性)。
     DELETE(DELETE):从服务器删除资源。
    还有两个不常用的HTTP动词。
     HEAD:获取资源的元数据。
     OPTIONS:获取信息,关于资源的哪些属性是客户端可以改变的。
    下面是一些例子。
     GET /zoos:列出所有动物园
     POST /zoos:新建一个动物园
     GET /zoos/ID:获取某个指定动物园的信息
     PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
     PATCH /zoos/ID:更新某个指定动物园的信息(提供该动物园的部分信息)
     DELETE /zoos/ID:删除某个动物园
     GET /zoos/ID/animals:列出某个指定动物园的所有动物
     DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

    6. 过滤信息(Filtering)

    如果记录数量很多,服务器不可能都将它们返回给用户。API应该提供参数,过滤返回结果。
    下面是一些常见的参数。
     ?limit=10:指定返回记录的数量
     ?offset=10:指定返回记录的开始位置。
     ?page=2&per_page=100:指定第几页,以及每页的记录数。
     ?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序。
     ?animal_type_id=1:指定筛选条件
    参数的设计允许存在冗余,即允许API路径和URL参数偶尔有重复。比如,GET /zoo/ID/animals 与 GET /animals?zoo_id=ID 的含义是相同的。

    7.状态码(Status Codes)

    服务器向用户返回的状态码和提示信息,常见的有以下一些(方括号中是该状态码对应的HTTP动词)。
     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 - [*]:服务器发生错误,用户将无法判断发出的请求是否成功。
    状态码的完全列表参见这里。

    8.错误处理(Error handling)

    如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。
    {
    error:"Invalid API key"
    }

    9.返回结果

    针对不同操作,服务器向用户返回的结果应该符合以下规范。
     GET /collection:返回资源对象的列表(数组)
     GET /collection/resource:返回单个资源对象
     POST /collection:返回新生成的资源对象
     PUT /collection/resource:返回完整的资源对象
     PATCH /collection/resource:返回完整的资源对象
     DELETE /collection/resource:返回一个空文档

    10.Hypermedia API

    RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么。
    比如,当用户向api.example.com的根目录发出请求,会得到这样一个文档。

    {"link":{
    "rel":"collection https://www.example.com/zoos",
    "href":"https://api.example.com/zoos",
    "title":"List of zoos",
    "type":"application/vnd.yourformat+json"
    }}
    上面代码表示,文档中有一个link属性,用户读取这个属性就知道下一步该调用什么API了。rel表示这个API与当前网址的关系(collection关系,并给出该collection的网址),href表示API的路径,title表示API的标题,type表示返回类型。
    Hypermedia API的设计被称为HATEOAS。Github的API就是这种设计,访问api.github.com会得到一个所有可用API的网址列表。
    {
    "current_user_url":"https://api.github.com/user",
    "authorizations_url":"https://api.github.com/authorizations",
    // ...
    }
    从上面可以看到,如果想获取当前用户的信息,应该去访问api.github.com/user,然后就得到了下面结果。
    {
    "message":"Requires authentication",
    "documentation_url":"https://developer.github.com/v3"
    }
    上面代码表示,服务器给出了提示信息,以及文档的网址。

    11.其他

    (1)API的身份认证应该使用OAuth 2.0框架。
    (2)服务器返回的数据格式,应该尽量使用JSON,避免使用XML。

    四. API服务器实现

    golang版本实现

    go web服务框架mux,参考设计实现一个 RESTful API 服务器

    C版本实现

    C版本一般调用libmacrohttpd库,官网:http://www.gnu.org/software/libmicrohttpd/。
    参考设计:基于libmicrohttpd的HTTP服务器初探如何直接获取 libmicrohttpd 库中POST上来的整个数据;edgex的device-sdk-c中也实现了调用libmicrohttpd实现的web服务调用,可供参考https://github.com/edgexfoundry/device-sdk-c。
    IBM的AXIS2/C也可实现REST API,参考:https://www.ibm.com/developerworks/cn/opensource/os-cn-axis2c/。

    五. 设计工具

    常用API设计工具有RAML、Swagger、Blueprint这三种工具,它们都是用来描述和辅助API开发的,只是它们之间的侧重有所不同。一些好的样例网站:
    https://api.datonis.io/apidoc/3.0/Sessions/api_sign_in.html
    https://github.com/edgexfoundry/edgex-go/blob/master/api/raml/core-data.raml  edgexraml

    RAML

    RAML(RESTful API Modeling Language 即 RESTful API 建模语言)是对 RESTful API的一种简单和直接的描述。它是一种让人们易于阅读并且能让机器对特定的文档能解析的语言。RAML 是基于 YAML,能帮助设计 RESTful API 和鼓励对API的发掘和重用,依靠标准和最佳实践从而编写更高质量的API。通过RAML定义,因为机器能够看得懂,所以可以衍生出一些附加的功能服务,像是解析并自动生成对应的客户端调用代码、服务端代码结构, API说明文档。
    RAML本质上可以理解为一种文档的书写格式。基于RAML语言,有不少辅助API开发的工具,这里特别推荐一下raml2html与api-console,它们都可以将raml源文件转换成精美的doc文档页面,其中raml2html转换结果是静态的,api-console则可以生产可直接交互的api文档页面,有些类似后面要说的Swagger。

    Swagger

    Swagger与RAML相比,RAML解决的问题是设计阶段的问题,而Swagger则是侧重解决现有API的文档问题,它们最大的不同是RAML需要单独维护一套文档,而Swagger则是通过一套反射机制从代码中生成文档,并且借助ajax可以直接在文档中对API进行交互。因为代码与文档是捆绑的所以在迭代代码的时候,就能方便的将文档也更新了。不会出现随着项目推移代码与文档不匹配的问题。另外Swagger是基于JSON进行文档定义的。

    API Blueprint

    API Blueprint是使用Markdown来定义API的,Markdown相比前面两个RAML、JSON门槛又降低了一大截。同时API Blueprint与前面的Swagger、RAML一样也能提供可视化的文档界面与Mock Server的功能。不过其Mock能力比较弱。

    参考:

    1. https://blog.csdn.net/u011935772/article/details/71480186

    2. https://www.cnblogs.com/galaxyyao/p/3797209.html

    3. 理解RESTful架构阮一峰

    4. RESTful API 设计指南阮一峰

    5. 实现一个 RESTful API 服务器  RSET和RPC比较

    6. API 设计: RAML、Swagger、Blueprint三者的比

    7. 使用Raml构建Restful API

    8. https://raml.org/

    9.   gRPC应用C++

    10. gRPC(HTTP / 2)比使用HTTP / 2的REST更快吗?  默认情况下,gRPC不比HTTP / REST更快,但它为您提供了更快的工具。有些事情对于REST来说很难或不可能做到。

    11.  面试问题:REST与RPC区别?

  • 相关阅读:
    【转载】关于C#中动态加载AppDomain的问题
    poj2239
    poj2231
    poj2229
    poj2234
    poj2236
    前 路
    只含一个单词的句子
    做人准则
    改变人生的32句励志名言
  • 原文地址:https://www.cnblogs.com/embedded-linux/p/9451753.html
Copyright © 2020-2023  润新知