REST是一种风格,而不是标准。因为既没有REST RFC,也没有REST协议规范或者类似的规定。REST架构是Roy Fielding(他也是HTTP和URI规范的主要作者之一)在一篇论文中描述的。REST并没有创造新的技术,组件或服务,隐藏在RESTful Web API背后的理念是使用Web的现有特征和能力。RESTful Web API定义了如何更好地使用现有Web标准中的一些准则和约束。本文首先介绍RESTful相关知识,然后以Atromic为例,介绍如何在ThinkPHP中开发具有鉴权功能的RESTful API。
RESTful基础知识
资源
资源是REST中最关键的抽象概念,它们是能够被远程访问的应用程序对象。一个资源就是一个标识单位,它可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在,任何可以被访问或被远程操纵的东西都可能是一个资源。资源可以是静态的,也就是该资源的状态永远不会改变。相反,某些资源的状态可能随着时间推移呈现很大的可变性。这两种类型的资源都是有效的。可以用一个URI(统一资源定位符)指向资源,每种资源对应一个特定的URI。要获取这个资源,访问它的URI就可以,因此URI就成了每一个资源的地址或独一无二的识别符。URI提供了Web通用的识别机制,它包含了客户端直接与被引用的资源进行交互时需要的所有信息。作为资源标识的URI最好具有“可读性”,因为具有可读性的URI更容易被使用,使用者一看就知道被标识的是何种资源,比如如下一些URI就具有很好的可读性。
使用“链接”关联相关的资源
在绝大多数情况下,资源并不会孤立地存在,必然与其它资源具有某种关联。既然我们推荐资源采用具有可寻址性的URI来标识,那么我们就可以利用它来将相关的资源关联起来。超链接常被客户端用于资源导航。
我们可以通过URI获取指定的Room,也可以获取Room下的Reservation。
统一资源接口
为了简化整体系统架构,REST架构风格包含了统一接口的概念。统一接口包含一组受限的操作,由它们进行资源的访问和操作。不论什么资源,都使用相同的接口。由于REST是面向资源的,所以一个Web API旨在实现针对单一资源的操作。我们在前面已经说个,针对资源的基本操作唯CRUD而已,这是使我们可以为Web API定义标准接口成可能。所谓的标准接口就是针对不同资源的Web API定义一致性的操作来操作它们,其接口可以采用类似于下面的模式。
使用标准的HTTP方法
由于RESTful Web API采用了同一的接口,所以其成员体现为针对同一资源的操作。对于Web来说,针对资源的操作通过HTTP方法来体现。我们应该将两者统一起来,是Web API分别针对CRUD的操作只能接受具有对应HTTP方法的请求。关于何时以及如何使用不同的HTTP方法,在Fielding的论文中没有描述。对于大部分方法,如GET或 DELETE,通过阅读HTTP规范就能清楚其含义,而对于POST和PUT,就不那么容易了。
重要方法 | 典型用法 | 典型状态码 | 安全 | 幂等 |
GET | 获取表示
变更时获取表示(缓存) |
200(OK) – 表示已在响应中发出 204(无内容) – 资源有空表示 301(Moved Permanently) – 资源的URI已被更新 303(See Other) – 其他(如,负载均衡) 304(not modified)- 资源未更改(缓存) 400 (bad request)- 指代坏请求(如,参数错误) 404 (not found)- 资源不存在 406 (not acceptable)- 服务端不支持所需表示 500 (internal server error)- 通用错误响应 503 (Service Unavailable)- 服务端当前无法处理请求 |
是 | 是 |
DELETE | 删除资源 | 200 (OK)- 资源已被删除 301 (Moved Permanently)- 资源的URI已更改 303 (See Other)- 其他,如负载均衡 400 (bad request)- 指代坏请求t 404 (not found)- 资源不存在 409 (conflict)- 通用冲突 500 (internal server error)- 通用错误响应 503 (Service Unavailable)- 服务端当前无法处理请求 |
否 | 是 |
PUT | 用客户端管理的实例号创建一个资源 通过替换的方式更新资源 如果未被修改,则更新资源(乐观锁) |
200 (OK)- 如果已存在资源被更改 201 (created)- 如果新资源被创建 301(Moved Permanently)- 资源的URI已更改 303 (See Other)- 其他(如,负载均衡) 400 (bad request)- 指代坏请求 404 (not found)- 资源不存在 406 (not acceptable)- 服务端不支持所需表示/p> 409 (conflict)- 通用冲突 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突) 415 (unsupported media type)- 接受到的表示不受支持 500 (internal server error)- 通用错误响应 503 (Service Unavailable)- 服务当前无法处理请求 |
否 | 是 |
POST | 使用服务端管理的(自动产生)的实例号创建资源 创建子资源 部分更新资源 如果没有被修改,则不过更新资源(乐观锁) |
200(OK)- 如果现有资源已被更改 201(created)- 如果新资源被创建 202(accepted)- 已接受处理请求但尚未完成(异步处理) 301(Moved Permanently)- 资源的URI被更新 303(See Other)- 其他(如,负载均衡) 400(bad request)- 指代坏请求 404 (not found)- 资源不存在 406 (not acceptable)- 服务端不支持所需表示 409 (conflict)- 通用冲突 412 (Precondition Failed)- 前置条件失败(如执行条件更新时的冲突) 415 (unsupported media type)- 接受到的表示不受支持 500 (internal server error)- 通用错误响应 503 (Service Unavailable)- 服务当前无法处理请求 |
否 | 否 |
HTTP 状态代码
HTTP定义了一套可以从API返回的有意义的状态代码。 这些代码能够用来帮助API使用者对不同的响应做出相应处理。常用的状态码如下:
- 200 OK (成功) – 对一次成功的GET, PUT, PATCH 或 DELETE的响应。也能够用于一次未产生创建活动的POST
- 201 Created (已创建) – 对一次导致创建活动的POST的响应。 同时结合使用一个位置头信息指向新资源的位置- Response to a POST that results in a creation. Should be combined with a Location header pointing to the location of the new resource
- 204 No Content (没有内容) – 对一次没有返回主体信息(像一次DELETE请求)的请求的响应
- 304 Not Modified (未修改) – 当使用HTTP缓存头信息时使用304
- 400 Bad Request (错误的请求) – 请求是畸形的, 比如无法解析请求体
- 401 Unauthorized (未授权) – 当没有提供或提供了无效认证细节时。如果从浏览器使用API,也可以用来触发弹出一次认证请求
- 403 Forbidden (禁止访问) – 当认证成功但是认证用户无权访问该资源时
- 404 Not Found (未找到) – 当一个不存在的资源被请求时
- 405 Method Not Allowed (方法被禁止) – 当一个对认证用户禁止的HTTP方法被请求时
- 410 Gone (已删除) – 表示资源在终端不再可用。当访问老版本API时,作为一个通用响应很有用
- 415 Unsupported Media Type (不支持的媒体类型) – 如果请求中包含了不正确的内容类型
- 422 Unprocessable Entity (无法处理的实体) – 出现验证错误时使用
- 429 Too Many Requests (请求过多) – 当请求由于访问速率限制而被拒绝时
表示
对资源的操纵永远是通过其表示实现的。资源可能永远不会在网络中传输,相反,传输的是资源的表示。资源的表示包括数据和描述数据的元数据,例如,HTTP头“Content-Type” 就是这样一个元数据属性。
通常使用XML,JSON或Atom来表征资源。通过设置“Accept”请求头,客户端就可以请求指定的表示编码。
RESTful Web API服务端程序必须根据HTTP规范返回状态码。状态码的第一个数字标识返回类型,1xx表示临时响应,2xx表示成功响应 ,3xx代表转发,4xx表示客户端错误,5xx代表服务端错误。使用错误的响应码,或者总返回200响应,并在消息主体中包含特定应用程序的响应,这两种做法都是不好的实践。
ThinkPHP对RESTful的支持
TP原生是不支持RESTful的,他是通过重载Controller类,在__Call方法中实现对Restful的支持
系统自动调用处理方式,就是根据当前请求类型和资源类型自动调用相关操作方法。系统的自动调用规则是:
定义规范 | 说明 |
---|---|
操作名_提交类型_资源后缀 | 标准的Restful方法定义,例如 read_get_pdf |
操作名_资源后缀 | 当前提交类型和defaultMethod属性相同的时候,例如read_pdf |
操作名_提交类型 | 当前资源后缀和defaultType属性相同的时候,例如read_post |
我们可以使用下面的模版来实现对资源的CRUD操作:
因为有操作名的存在,此时TP并不能完全按照RESTful的资源规则来发送请求,需要在URL中加入操作名,如对id=1的user的资源获取,其URL格式为
而我们希望得到的URL是
这就需要用到REST路由定义,我们定义下面的路由
就能通过RESTful风格的URL正常获取到资源。
Atromic中具备鉴权功能的RESTful Web API实践
定义Controller
我们以用户登录、登出为例,首先定义符合RESTful规则的Controller,我们采用json数据表示资源。定义两个方法为login_post和logout_post,他们分别是登录和登出的处理方法,都只接收POST动作请求。
设置路由
我们要求URL的RESTful请求规则如下
在config.php文件中开启路由,并定义路由规则
配置Nginx
通过定义Rest风格的Controller和Rest路由,我们的URL变为了这样
配置ThinkPHP的URL模式工作在REWRITE模式下,同时配置Nginx去掉URL地址里面的入口文件index.php
最终我们请求的URL成为符合RESTful规范的格式
鉴权功能的实现
虽然我们请求的资源的URL是RESTful风格,但是在处理该请求的Controller里面,还是按照TP的action规范来编写处理函数的,如我们对 http://www./User/1 的请求,最终转换到UserController中的read_get方法来处理,因此我们在对 http://www./User/1 进行权限检查时,实际上就是对 http://www./User/readGet进行权限检查权,因此可以按照TP提供的Auth权限认证类来进行权限检查处理。
Auth权限认证是按规则进行认证。在数据库中有规则表(think_auth_rule),用户组表(think_auth_group), 用户组用户关系表(think_auth_group_access)。在规则表中定义权限规则,在用户组表中定义每个用户组有哪些权限规则,在用户组用户关系表中定义用户所属的用户组。
添加认证规则
数据表:think_auth_rule
其中name是最重要的字段:模块/控制器/方法。顺序不能改变,大小写随意。Auth类中会统一转成小写。其次是type。一般情况下设定为1。(最后存入用户权限的就是type为1的规则)、
添加用户组(角色)
数据表:think_auth_group
其中rules字段最为重要,就是控制哪个组有哪些权限。
添加用户和组对应关系
此表实际上就是member和auth_group的中间表,
规定哪个用户(uid)属于哪个组(group_id)
然后继承RestController作为所以控制器的基类,在_initialize函数中进行权限检测,代码中高亮部分为权限检测的核心。如果用户未登录HTTP状态返回401,如果权限检测结果为不具备该权限HTTP状态返回403。
参考文献
(1)artech 《我所理解的RESTful Web API [设计篇]》:http://www.cnblogs.com/artech/p/3506553.html
(2)Gregor Roth 《RESTful HTTP的实践》:http://www./cn/articles/designing-restful-http-apps-roth/
(3)ThinkPHP 《ThinkPHP3.2完全开发手册——RESTFul》:http://document./manual_3_2.html#restful
(4)luofei614 《 比RBAC更好的权限认证方式(Auth类认证)》:http://www./topic/4029.html
(5)haran 《跟haran一起学习Auth认证方法的使用》 :http://www./topic/9679.html
- 本文固定链接: http://www./thinkphp-restful-web-api/
- 转载请注明: subjectwa 于 Eureka 发表