重新认识Rest

微服务架构已经很流行, 从概念上要解决的问题: 认识一个系统,如何将这个系统划分(系统的分解),识别出组件, 组件之间如何通讯,信息如何交换,使得协同完成一件事情。 同样还要包括,随着系统的演变,组件如何演化。

那么组件(模块或服务)本身的抽象,以及如何暴露,如何和外部通讯,如何数据交换,以及如何交互?这些都需要面对解决的问题, 重读Roy论文,重新认识到Rest对于上面的问题(组件如何暴露,如何通讯,如何交换数据,以及模块的演化)给出一个答案。下面谈谈自己对Rest的理解。

一切皆资源(resource)

Rest是面向资源的架构ROA( resource -oriented architecture),理解resource这个概念非常重要,或者这个是理解Rest的核心。Rest 是一种理念,将现实世界一切抽象为资源,通过资源将现实世界映射到数字世界; 就如同面向对象,将现实世界一切抽象为对象,通过对象将现实世界映射到数字世界。 比如电商里面的一个商品,一个订单,一个快递单号,甚至一条评论都可以抽象为资源;更抽象点概念,比如提供在线打印的服务,每一个打印的请求也是一个资源; 一个调度引擎,每一次调度的请求都一个资源。

在资源为基本的抽象单元世界里,资源有这么些特性:

1. 每一种现实客观事物都可以抽象为资源;资源就是现实世界的抽象的属性的信息实体。

2. 每一种资源都有一个标识, 或者有多个标识, 就是资源的名字;

3. 在给定的上下文,可以通过名字查找到资源本身;( 资源本身的名字,与物理实现分离)

4. 计算是将资源具体化到表现层;

5. 资源本身具有不可变性;

6.  对于不同表现层之间的转换时无损的,之间可以等价转换;

7. 计算结果也是一种资源,也有其标识符。

在web世界里面多有一一对应。 #1 是相同的理念;#2 资源标识就是URI ; #3 通过就是DNS查找到资源; #4 对应动态资源计算就是一个请求,通过计算转换为表现层数据给用户; #5 资源本身逻辑上保持不变; #6 不同表现层是等价的(xml,json); #7 对于计算出来的结果,也是一种资源;   

通过客观世界映射到数字世界,那么客观世界中的互操作,如何体现。下面分别介绍,对象如何被访问(URI),对象如何操作(CRUD),以及信息数据如何交换。

URI (统一资源识别符)

 资源如何被访问?或者资源如何将资源暴露外部世界? 这个就是URI,这个天生就于Web紧密连接在一起的,被用作资源的名字。 

比如对一个手机的描述 http://hostname:80/products/smartphone, 清晰明了这是一个smarphone的产品,同时可以通过URI,找到获取信息本身。(URI与URL往往一致)。这个是被认为理所当然或者已经熟视无睹,但是理所当然的事情都不是这么的简单的。 比对一下,看看书的URI(ISBN)与URI比较, 看看哪一个可读性好一些?

http://hostname/books/爱丽丝梦游仙境

ISBN:7-301-04815-7 

URI是资源的名字,就说说名字本身。比如一个资源

http://host/products/smartphone

http://host/products 也可以理解为名字在网络上的namespace。名字很显然是一个名词性质的词语, 试试想想一个动词的名字是什么感觉:); 同样名字与其实现没有关系,下面的名字将概念和实现耦合在一起,不是好的名字。

http://host/books/xxx.asp

http://host/books/xxx.php

 同样名字要名副其实,这个是程序员程序员的品味和修炼有关,不在本文范围里面,暂且不讨论。

统一的方法(CRUD)

Rest 将对于资源的操作定义为CRUD(get/post/put/delete),是的,是所有的操作!或许这样说更容易理解一些,相当面向对象里面所有的对象的方法,当且仅当只有CRUD操作。先回顾一下这个四个操作的定义,然后再看如何统一所有操作.

get: 对应读操作,获取资源;语义很清晰,只读应该不期望改变资源本身。

post: 创建一个资源。 因为资源ID一般是服务创建的,服务器创建成果会返回新的ID,这为一个不等幂操作。

put:  更新资源。 这个需要提交一个完整的资源,当然包括ID,才能更新。这个操作经常会和post搞混。 (post就是没有完整信息比如ID,就只能由服务器创建,put是有ID可以提交更新)。 等幂操作。

delete: 删除资源。 等幂操作。

幂等操作(idempotentance),简单理解一个操作(函数映射)多次,和映射一次效果一样。 

f(f(x)) = f(x)

operation vs status

如何将所有的操作统一到CRUD上呢? 比如对于一个订单,我们有增删改查,这个很好理解与CRUD一一对应。但是对于此外的,比如取消,锁定一个订单如何对应? 对于传统的OO理念我们会定义一组操作:

class OrderManager{

cancelOrder( int id){...}

 lockOrder(int id) {...}

}

对于SOAP,RPC我们经常都是这么做的,暴露出方法。

对于Rest里面我们把操作当成一个状态的修改。对于上面的Cancel方法在rest里面可以这样定义

put  http://host/books/xxx  

body: {  "status": "cancel"}

这样就将操作转换为状态变化,只要提供状态修改的方法,更新操作(put), 就可以统一所有类似的操作。貌似一个很简单的转化就可以将所有的操作统一,还是很是强大。

既然CURD可以完全统一所有对资源的操作,那么很显然CRUD可以借助于HTTP协议的动词来实现。很是完美,谁让Roy T. Fielding就是http协议和Rest概念的提出者。

既然通过URI来访问资源,所有的操作http动词可以来操作。下一个问题就是信息如何交换。

Representation(表现层)

数据是信息的载,而数据本身可以有不同表现形式 如xml,json,yaml,binary。 那么服务之间如何信息的交换,就是通过表现层来交换。先看看传统的rpc,数据如何传输?数据的格式,对象的本身都在开发的时候定义好。 这样使得客户端和服务器都绑定在一起,没有办法单独演化升级。而对于Rest定义客户端和服务器对于数据可以根据客户端的请求来返回(Content -type),同样服务器端可以支持不同的格式。 同样之间还可以协商机制确定如何传递数据。 这样服务器与客户端解耦,可以独立升级, 独立演化,是软件架构追求一致追寻的目标。

Stateless (无状态)

互联网上资源天生就可以任何时间任何地点的可以访问,其访问弹性是不受控制的。如何做到弹性,这个一个挑战. 试试想想一般的程序如果要做到弹性计算,而不用去改代码,不是一般挑战。 无状态很好的适应这样的场景。

在互联网上,客户端浏览器发送URL请求到服务器,服务器接受请求响应返回给客户。 如何客户访问量陡增,比如双11, 服务器就通过扩展来并发处理。如果请求是没有状态的, 就可以被分发到不同的服务器,服务器只需要根据请求的本身去应答,而不去考虑请求的上下文。如果有状态,那么处理起来就复杂很多,服务器需要根据请求查找上下文,如果处理的服务器没有上下文,就需要同步上下文。更进一步,状态更新,如何保证上下文一致。这些带来的复杂度,往往就是bug,影响到开发效率,提高维护成本。 另外,这样上下文相关对于缓存也没有存在同样的问题。

当然天下没有免费的午餐。 没有状态就需要对相应每一次客户端在请求的时候,需要额外的信息来标识自己,cookie或者额外的参数。 很显然rest不是最优的传输效率不是最高的。 比起来带来的可扩展性,好处远远大于那点额外的带宽占用。

HATEOAS

(Hypermedia As The Engine of Application State)

超链接就是一个应用程序状态引擎。这个是Rest对API的约束, 让服务器和客户端进一步交互上解耦。这个和传统的分布式应用交互不太一样。 比如rpc,预先定义一组api,然后客户端只能根据预先定义的api来与服务器之间交互,这样服务器和客户端之间就产生依赖,二者不能独自演化。

Rest API 对于每一个api返回值,不但需要告诉返回哪些值,同样还需要告诉下一步有哪些交互,交互的信息是通过超文本。这样子从一个起始点api就可以根据返回相关的超链接,来进行下一步操作。理想的这样所有的流程都可以通过一个api,根据超文本连接完成。貌似爬虫很喜欢:)

这里有一个例子

下面是个例子,首先是一个GET请求账户的信息

    GET /account/12345 HTTP/1.1

    Host: somebank.org

    Accept: application/xml

将会返回 :


HTTP/1.1 200 OK

Content-Type: application/xml

<account>

<account_number>12345< /account_number>

<balance currency="usd">100.00 </balance>

<link rel="deposit" href="https://somebank.org/account/12345/deposit" / link> <rel="withdraw" href="https://somebank.org/account/12345/withdraw" / link><rel="transfer" href="https://somebank.org/account/12345/transfer" / link>              <rel="close" href="https://somebank.org/account/12345/close" />

</account>

这样用户可以通过返回值中的URL,做下一次操作。 这样交互不需预定义API。 碰到的大多数见到的rest API,这一点都不满足,被称为restful.

本文回顾一下Rest 理念(一切皆资源),以及rest api的五大原则(URI,Uniform operation, representation,stateless 和 HATEOAS ) 。

https://stackoverflow.com/questions/152871/isnt-resource-oriented-really-object-oriented

https://www.w3.org/People/Connolly/9703-web-apps-essay.html

http://resources.1060research.com/docs/IntroductionToResourceOrientedComputing-1.pdf

https://www.ics.uci.edu/~fielding/pubs/dissertation/top.htm

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

推荐阅读更多精彩内容