RESTful 架构 (表现层状态转移)

理解由来

概念是 Roy Thomas Fielding在他2000年的博士论文中提出的。他参与制定了 HTTP 1.0 和 HTTP 1.1 协议。

他希望能基于网络现有的协议基础上创建一个功能强大,性能游戏,适宜通信的架构。

概念

客户端 - 服务器分离(Client - Server)

如含义一样,将从逻辑上将业务实现拆分为客户端与服务端实现。

通过分离设计,能简化两边的设计复杂度,提高其可扩展性。

资源(Resources)

资源是 RESTful 的主体,主要指代互联网上的一个实体,可以是一段文本、一张图片、一首歌曲、一种服务,总之就是一个具体的实在。资源通过 URI 来唯一标识。

表现层(Representation)

资源的信息载体形式,叫做表现层。他可以是文本、XML、JSON 或者是一个二进制文件。它的具体表现形式,应该在HTTP请求的头信息中用Accept和Content-Type字段指定,这两个字段才是对"表现层"的描述。

状态转化(State Transfer)

互联网通信协议HTTP协议,是一个无状态协议。这意味着,所有的状态都保存在服务器端。因此,如果客户端想要操作服务器,必须通过某种手段,让服务器端发生"状态转化"(State Transfer)。而这种转化是建立在表现层之上的,所以就是"表现层状态转化"。

在 HTTP 中,我们一般通过四种 HTTP 动词(verb)来对应资源的变化:GET用来获取资源,POST用来新建资源(也可以用于更新资源),PUT用来更新资源,DELETE用来删除资源。

相应的状态的交互应当是无状态的(ServerLess)这是 HTTP 的特性所决定的,要求每次请求包含服务器需要的所有信息,这样可以很好的确保每一次变化的可预测性,进而提高可靠性,也能增进可扩展性。

综述

综合上面的解释,我们总结一下什么是RESTful架构:

(1)每一个URI代表一种资源;

(2)客户端和服务器之间,传递这种资源的某种表现层;

(3)客户端通过四个HTTP动词,对服务器端资源进行操作,实现"表现层状态转化"。

HTTP 与 RESTful

HTTP 请求是互联网架构中重要的一环,其在 TCP 连接的基础上,实现了语义化,缓存机制,无状态等等特性。在互联网上也有不错的性能,REST 常常会基于 HTTP 协议的基础上实现其核心概念。

论文中对 HTTP 与 REST 相适宜的论述提及了几点:

  1. 可扩展性:主要是协议的 method,返回状态码,协议向下兼容性
  2. 自我信息描述:主要是从 URI 能准确定义资源,Content-type HTTP 头能准确定义表现层,还有相关语义化的 HTTP 头。
  3. 性能:主要从 HTTP 高于网络层,在实现上能复用 TCP 连接,减少 TCP 建立与销毁的时间成本。还有就是 HTTP 其容易缓存的特性。

这里是论文中对 HTTP Code 来表现业务相应状态的相关表述:

论文中关于 HTTP 状态码与 RESTful 适配的论述

Matin Fowler 关于 RESTful 的成熟度模型

原文: https://martinfowler.com/articles/richardsonMaturityModel.html

他讲这个模型层次分为四级,大概如下所示:

RESTful 成熟度模型

Level 0

利用 HTTP 协议做数据交换,所有的参数描述通过 url 或者 POST body 形式通知服务器,返回相应的数据,此级别通常都是基于 。实质上就是基于 HTTP 的 RPC(远程过程调用),具体交付的细节完全由相关规范或团队内部约定解决。

根据理解设计了一份请求交互:

POST /apiService

{
    "action": "bookMeeting",
    "roomID": "Roma",
    "guestIDs": ["Roy", "Tom"],
    "from": "201805221400",
    "to": "201805221500"
}

------- Response

{
    "status": "succuess",
    "guestIDs": ["Roy", "Tom"],
    "meetingID": "201805221400-201805221500-Roma"
}

Level 1

将 API 按照 RESTful 中资源的方式进行划分,初步有了自我描述(self description)的特性了,客户端可以对相关的资源进行更加细致的操作。

根据理解设计了一份请求交互:

POST /apiService/room/Roma

{
    "action": "bookMeeting",
    "guestIDs": ["Roy", "Tom"],
    "from": "201805221400",
    "to": "201805221500"
}

------- Response

{
    "status": "succuess",
    "guestIDs": ["Roy", "Tom"],
    "meetingID": "201805221400-201805221500-Roma"
}

Level 2

这个级别有更加进一步的利用了 HTTP 的特性,增加了对 HTTP verb (比如 GET 表示查询、POST 表示创建、PUT 表示修改、DELETE 表示 等等)的运用,并且运用原有的 HTTP response status 来表征业务上请求的成功与失败,一般项目常见的 RESTful 运用基本都接近这个级别。

这个请求基本就和我们平时使用的 RESTful api 很接近了:

POST /apiService/room/Roma

{
    "guestIDs": ["Roy", "Tom"],
    "from": "201805221400",
    "to": "201805221500"
}

------- Response

status: 201

{
    "guestIDs": ["Roy", "Tom"],
    "meetingID": "201805221400-201805221500-Roma"
}

Level 3

这个基本也称作 HATEOAS (Hypertext As The Engine Of Application State),这个级别是 RESTful 最复杂的实现,这个级别最理想的情况是,不需要特别复杂 API 文档进行描述的,这里的 API 设计最大化的实现了 RESTful 的自我描述特性。这种方案虽然引入很大的复杂性,但是最大限度的将 API 设计变得配置化了,所有 API 设计将会基于更加抽象的工作流设计了,稍后再做解释:

本阶段的相关请求模型大概是这样的:

GET /apiService/room

---- Response
{
    roomList: [
        {
            meetingID: "Roma",
            __link: [
                {
                    method: "POST",
                    url: "/apiService/room/Roma",
                    parameters: {
                        guestIDs: "[guestID]",
                        from: "timestamp",
                        to: "timestamp"
                    }
                }
            ]
        },
        ...
    ]
}


------------


POST /apiService/room/Roma

{
    "guestIDs": ["Roy", "Tom"],
    "from": "201805221400",
    "to": "201805221500"
}

------- Response

status: 201

{
    "meetingID": "201805221400-201805221500-Roma"
    _links: [
        {
            url: '/apiService/meeting/201805221400-201805221500-Roma',
            methos: 'GET'
        },
        ...
    ]
}

可以看出,从查询到最终结果,都是由第一个 api 的返回的资源列表和操作项,引导向后面的操作,这样,后端在设计 API 的时候,需要考虑从一条业务 workflow 的角度去设计。这样只要整个流程不变,局部的数据变化,只需要修改后端的相关配置即可,这样业务可以很大程度的配置化。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,100评论 18 139
  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 170,567评论 25 707
  • 不知道换了个画风大家还认得出包哥不 他强烈要求以后就用这个 “帅得一哔”的画风 我当然不会满足他啊 今天也是包哥基...
    素菜包阅读 587评论 8 6
  • 如果再也见不到你,那么祝你早安,午安,晚安。 公寓门口的广式早点以后不来了,难过。回想起它带给我的满足,感谢每一段...
    GEMLin阅读 226评论 0 0
  • 感谢电脑时代,到点自动关账,所以有了元旦的休息日,感谢这个伟大的时代。 假期里几场同学聚会我都没有参加,第一和大家...
    mimi播报阅读 376评论 1 7