博客源为书写的载体,书写以对思维的缓存 正文

RESTful


REST:表述性状态传递(Representational State Transfer,简称REST),是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。表述性状态转移是一组架构约束条件和原则。满足这些约束条件和原则的应用程序或设计就是RESTful。时至今日RESTful架构风格已成为企业级服务的标配。

一:什么是RESTful

1.RESTful与技术无关,代表的是一种软件架构风格。

2.RESTful从资源的角度类审视整个网络,它将分布在网络中某个节点的资源通过URL进行标识,客户端应用通过URL来获取资源的表征,获得这些表征致使这些应用转变状态。

3.所有的数据,无论是通过网络获取的还是操作(增删改查)的数据都是资源,将一切数据视为资源是REST区别与其他架构风格的最本质属性。

4.对于RESTful这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)。

5.RESTful是一种规范,或者说是一种建议。

二:RESTful API设计风格(10项建议)

1.通信协议

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

原因当然是HTTPS安全,这里插个嘴,为什么HTTPS比HTTP更安全呢?

(1).HTTP为什么不安全?

HTTP协议属于明文传输协议,交互过程以及数据传输都没有进行加密,通信双方也没有进行任何认证。所以通信过程非常容易遭遇劫持、监听、篡改,严重情况下,会造成恶意的流量劫持等问题。

(2).HTTPS为什么安全?

HTTPS解决了HTTP带来的问题:引入加密以及身份验证机制。服务器给客户端的传输数据是密文的,只有服务器和客户端才能读懂,保证了数据的保密性。同时在交换数据之前,验证一下对方的合法身份,保证通信双方的安全。

详细内容请参考:https://blog.csdn.net/xifeijian/article/details/54667989

2.域名

现在企业开发很多都是前后端分离,前后端各自分工,协同敏捷开发。后端提供RESTful API并给出详细文档说明,前端人员发送API请求获取数据后渲染页面。那么前端在处理前端页面和获取后端数据时域名必须得区分:

方式一:子域名方式(会存在跨域问题)

        用户访问:https://www.helloworld.com

        获取数据:https://api.helloworld.com

方式二:URL上进行区分(推荐)

        用户访问:https://www.helloworld.com

        获取数据:https://www.helloworld.com/api/

3.版本

项目会进行版本迭代,版本之间存在共存的情况,因此RESTful建议将API的版本号放入URL,如:

        https://www.helloworld.com/api/v1/    # v1:版本1

        https://www.helloworld.com/api/v2/    # v2:版本2

4.URI

在RESTful中的设计思想:面向资源编程(网络上的任何东西都是资源),而用一个URI(统一资源定位符)去指向资源,即每个URI都对应一个特定的资源。要获取这个资源访问它的URI就可以,因此URI就成了每一个资源的地址或识别符。一般每个资源至少有一个URI与之对应,最典型的URI就是URL。也就是说我们通常用URL来表示资源,而资源均使用名词来表示(可复数)。

        https://www.helloworld.com/api/v1/students/    # 表示多个学生

        https://www.helloworld.com/api/v1/courses/      # 表示多门课程 

5.Method

RESTful架构风格规定,数据的操作CRUD分别对应于HTTP方法:

GET用来获取资源,POST用来新建资源,PUT用来更新资源,DELETE用来删除资源。

这样就统一了数据操作的接口,仅通过HTTP方法,就可以完成对数据的所有增删查改工作。具体如下:

        GET:从服务器取出资源(一项或多项)

        POST:在服务器新建一个资源

        PUT: 在服务器更新资源(客户端提供完整资源数据--全部更新)。

        PATCH:在服务器更新资源(客户端提供需要修改的资源数据--局部更新)

        DELETE:从服务器删除资源

所以对于数据的增删改查我们通过不同的HTTP方法来表示,例如获取学生信息:

GET方式请求:https://www.helloworld.com/api/v1/students/这个URL即可。

6.过滤,通过在URL上传参的形式传递搜索条件

        https://www.helloworld.com/api/v1/students/?limit=10:指定返回记录的数量

        https://www.helloworld.com/api/v1/students/?offset=10:指定返回记录的开始位置

        https://www.helloworld.com/api/v1/students/?page=2&per_page=100:指定第几页,以及每页的记录数

        https://www.helloworld.com/api/v1/students/?sortby=name&order=asc:指定返回结果按照哪个属性排序,以及排序顺序

        https://www.helloworld.com/api/v1/students/?student_type_id=1:指定筛选条件

7.状态码

状态码     说明             详情

100         继续             请求者应当继续提出请求。服务器已收到请求的一部分,正在等待其余部分。
101      切换协议         请求者已要求服务器切换协议,服务器已确认并准备切换。
200         成功             服务器已成功处理了请求。
201       已创建            请求成功并且服务器创建了新的资源。
202       已接受            服务器已接受请求,但尚未处理。

203    非授权信息        服务器已成功处理了请求,但返回的信息可能来自另一来源。
204       无内容            服务器成功处理了请求,但没有返回任何内容。
205      重置内容         服务器成功处理了请求,内容被重置。
206      部分内容         服务器成功处理了部分请求。
300      多种选择         针对请求,服务器可执行多种操作。
301      永久移动         请求的网页已永久移动到新位置,即永久重定向。
302      临时移动         请求的网页暂时跳转到其他页面,即暂时重定向。
303  查看其他位置      如果原来的请求是 POST,重定向目标文档应该通过 GET 提取。
304      未修改            此次请求返回的网页未修改,继续使用上次的资源。
305    使用代理          请求者应该使用代理访问该网页。
307   临时重定向        请求的资源临时从其他位置响应。
400     错误请求          服务器无法解析该请求。
401      未授权            请求没有进行身份验证或验证未通过。

403    禁止访问           服务器拒绝此请求。
404     未找到             服务器找不到请求的网页。

405    方法禁用           服务器禁用了请求中指定的方法。
406      不接受            无法使用请求的内容响应请求的网页。
407  需要代理授权      请求者需要使用代理授权。
408     请求超时          服务器请求超时。
409        冲突              服务器在完成请求时发生冲突。
410      已删除            请求的资源已永久删除。
411   需要有效长度     服务器不接受不含有效内容长度标头字段的请求。
412   未满足前提条件  服务器未满足请求者在请求中设置的其中一个前提条件。
413   请求实体过大     请求实体过大,超出服务器的处理能力。
414   请求 URI 过长    请求网址过长,服务器无法处理。
415   不支持类型        请求的格式不受请求页面的支持。
416   请求范围不符     页面无法提供请求的范围。
417   未满足期望值     服务器未满足期望请求标头字段的要求。
500   服务器内部错误 服务器遇到错误,无法完成请求。
501     未实现             服务器不具备完成请求的功能。
502     错误网关          服务器作为网关或代理,从上游服务器收到无效响应。
503   服务不可用        服务器目前无法使用。
504     网关超时         服务器作为网关或代理,但是没有及时从上游服务器收到请求。
505      HTTP             版本不支持 服务器不支持请求中所用的 HTTP 协议版本。

红色标注为常用的状态码。状态码用于给用户提示与反馈信息,但是实际开发中状态码是远远不够用的,单纯的状态码无法涵盖所有的错误和异常。所以通常状态码还需要结合"code"来使用,例如如果出现错误,返回一个code。比如我通常是这么定义的:
58f9b3c700019d8c05750412.png

8.错误处理:出现错误应给用户返回错误信息,通常将"error"当做key

        {

            error: "错误信息"

        }

9.返回结果,针对不同操作,服务器向用户返回的结果应该符合以下规范

        GET /collection/:返回资源对象的列表

                例如:以订单(order)为资源对象, GET /order/:返回所有的订单


        GET /collection/resource/:返回单个资源对象

                 例如:GET /order/1/:返回单个订单,订单编号为1


        POST /collection/:返回新生成的资源对象

                例如:POST /order/:创建订单成功,将新生成的订单对象返回给前端


        PUT /collection/resource/:返回完整的资源对象

                例如:PUT /order/1/:将更新的订单对象返回给前端(全部更新)


        PATCH /collection/resource/:返回完整的资源对象

                例如:PATCH /order/1/:将更新的订单对象返回给前端(局部更新)


        DELETE /collection/resource/:返回一个空文档

                例如:DELETE /order/1/:返回空即代表删除成功

10.Hypermedia API,RESTful API最好做到Hypermedia,即返回结果中提供链接连向其他API方法,使得用户不查文档也知道下一步应该做什么。

前端GET请求获取订单列表:GET /order/,后端返回Json数据:
[
   {
       "id" : 1,
       "name" : "apple",
   },
   {
       "id" : 2,
       "name" : "banner",
   },
   ......
]
假如我们要获取订单的详细信息,就需要GET /order/1/
RESTful就建议你在返回结果中提供链接连向其他API方法,例如在访问GET /order/时将订单的详细信息的URL添加到:
[
   {
       "id" : 1,
       "name" : "apple",
       "url" : https://www.helloworld.com/api/v1/order/1/,
   },
   {
       "id" : 2,
       "name" : "banner",
       "url" : https://www.helloworld.com/api/v1/order/2/,
   },
   ......
]
这样我们如果想获取详细信息就不必再去拼接URL了。

三:基于Django的简单实现

路由:

urlpatterns = [
  url(r'^user/$', UserView.as_view()),
]

视图:

from django.views.generic.base import View
from django.http import JsonResponse

class UserView(View):
   def get(self, request, *args, **kwargs):
       result = {
           'status': success,
           'data': 'response data'
       }
       return JsonResponse(result, status=200)

   def post(self, request, *args, **kwargs):
       result = {
           'status': success,
           'data': 'response data'
       }
       return JsonResponse(result, status=200)
       
   def put(self, request, *args, **kwargs):
       result = {
           'status': success,
           'data': 'response data'
       }
       return JsonResponse(result, status=200)

   def delete(self, request, *args, **kwargs):
       result = {
           'status': success,
           'data': ''
       }
       return JsonResponse(result, status=200)

是的,通过CBV(基于类的视图)就能够实现RESTful API。如果要开发RESTful接口推荐使用Django rest framework框架:用于构建Web API的强大而又灵活的工具。

四:总结

RESTful用一句话来总结就是:URL定位资源,用HTTP描述操作。它让你能做到看URL就知道要什么、看http method就知道干什么、看http status code就知道结果如何。

五:最后

70478834facc725b.gif

    • 曹达华13 2019年9月18日 20:37
    • 大佬!