应用之间的通讯可以使用Web Services,也可以使用REST(表述性状态转移),后者因为轻量级和优雅而颇受欢迎,REST基于Http,实际上就是一套对HTTP/URI的最佳实践套路。在设计应用时能坚持REST原则,那就预示着你将会得到一个使用了优质架构的系统。

使用REST,套路分解为五条原则:

  1. 为资源定义ID

  2. 充分使用ID来做链接

  3. 使用标准动词

  4. 资源可以有多重表达形式

  5. 无状态

定义ID

从需求文本中提取名词和动词是一条设计的捷径。比如在电子商务应用中的一段需求描述:“客户可以点击列表内的订单,查询获得此订单”。那么订单(order)就是一个名词。定义ID也就是让每个订单可以有一个ID来标识它。使用REST,标识的方式是这样的:

http://example.com/order/1
http://example.com/order/2

分别表明查询1号订单、2号订单。类似的,对于客户、商品,可以如此表达:

http://example.com/customer/1234
http://example.com/product/4554

哦我去,那不是等于这玩意吗:


 class OrderManager{
     Order get(id:integer);
 }

OrderManager.get(1)

而且前面还多了一个方案(http://)和主机(example.com) ,好啰嗦。然而,好处就体现在这个啰嗦里面了:

  1. 利用已被定义,现成的方案,易于理解的规则。

  2. 在全球范围中一直在运行的。你的订单可以来自example.com,或者其他叫做foo.com,bar.com之类的镜像站上,它们可能分布到全球各地。

  3. 利用现有的工具。比如订单的链接可以被多种渠道分享到朋友那里,或者加入到浏览器的书签中

处理单数名词外,还有复数的,就是一组资源,类似这样的:

http://example.com/orders/2007/11
http://example.com/products?color=green 

对一类事物集合的标识。

充分利用链接表达资源和动作

链接是我们在HTML中常见的概念,但还可以更加通用。如下XML片段把对应order的product和customer链接进来:

<order self="http://example.com/customers/1234"> 
   <amount>23</amount> 
   <product ref="http://example.com/products/4554"> 
       <customer ref="http://example.com/customers/1234"> </customer> 
    </product>
</order>

应用程序可以由此XML“跟随”链接检索product和customer的更多数据。

还可以通过链接加入对资源的动作。比如你的账户还有100美元的情况下,你可以做存款取款转账四个操作:

GET /account/12345 HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0"?>
<account>
    <account_number>12345</account_number>
    <balance currency="usd">100.00</balance>
    <link rel="deposit" href="/account/12345/deposit" />
    <link rel="withdraw" href="/account/12345/withdraw" />
    <link rel="transfer" href="/account/12345/transfer" />
</account>

要是你的账户已经赤字,你可以做的动作就只有存款了:

GET /account/12345 HTTP/1.1

HTTP/1.1 200 OK
<?xml version="1.0"?>
<account>
    <account_number>12345</account_number>
    <balance currency="usd">-25.00</balance>
    <link rel="deposit" href="/account/12345/deposit" />
</account>

这个动作清单是和状态有关的,术语叫做HATEOAS (Hypertext As The Engine Of Application State) 。

使用标准方法

我们已经提过,”从需求文本中提取名词和动词”,名词说了,就是资源的命名。动词呢。比如对订单的“查询”就是动词。

http://example.com/order/1

在REST内默认就是GET,也就是“查询”。使用浏览器的场合,上面的URI在发给服务器时,会被翻译为

GET http://example.com/order/1

语义上来说,就是查询在example.com上的ID为1的订单,使用http协议。当使用这套,在服务器放准守REST的话,你还可以得到额外的好处,就是:

幂等。如果你发送了一个GET请求没有得到结果,你可能不知道原因是请求未能到达目的地,还是响应在反馈的途中丢失了。幂等性保证了你可以简单地再发送一次请求解决问题。
缓存。所以在很多情况下,你甚至不需要向服务器发送请求。

GET在HTTP中被叫做动词(verb),除了GET,还有POST之外,还有PUT、DELETE、HEAD和OPTIONS。作为OO开发者的话,就可以想象到RESTful HTTP方案中的所有资源都继承自类似于这样的一个类:

class Resource {
     Resource(URI u);
     Response get();
     Response post(Request r);
     Response put(Request r);
     Response delete();
} 

幂等性同样适用于:

  1. PUT。语义为:更新资源数据,如果资源不存在的话,则根据此URI创建一个新的资源

  2. DELETE。语义为:删除一个资源,或者删除不存在的东西没有任何问题

POST方法,通常表示“创建一个新资源”,也能被用于调用任意过程,因而它既不安全也不具有幂等性。

为什么使用标准方法如此重要?从根本上说,它使你的应用成为Web的一部分,统一接口也使得所有理解HTTP应用协议的组件能与你的应用交互。通用客户程序(generic client)就是从中受益的组件的例子,例如curl、wget、代理、缓存、HTTP服务器、网关还有Google、Yahoo!、MSN等等。

无状态通信

REST要求状态要么被放入资源状态中,要么保存在客户端上。或者换句话说,服务器端不能保持除了单次请求之外的,任何与其通信的客户端的通信状态。

这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态,那么大量的客户端交互会严重影响服务器的内存可用空间(footprint)。

资源多重表述

同样一个order资源,可能响应检索的格式是xml,为了轻量级的支持移动app,现在需要支持json。这样的资源表达方式变化可以直接利用HTTP内容协商(content negotiation),而无需自己定义参数。比如本来的请求包:

GET /order/1 HTTP/1.1
Host: example.com 
Accept: application/vnd.mycompany.order+xml  

现在可以让移动客户端发出:

GET /order/1 HTTP/1.1
Host: example.com 
Accept: application/vnd.mycompany.order+json

返回的响应包内,可以在其HTTP Content-type头中包含着数据类型。

才有已有标准的好处是客户端和服务器都可以更好的达到互换:
如果客户程序对HTTP应用协议和一组数据格式都有所“了解”,那么它就可以用一种有意义的方式与世界上任意一个RESTful HTTP应用交互。
倘若从客户端传来的数据符合应用协议,那么服务器端就可以使用特定的格式处理数据,而不去关心客户端的类型

原文: https://www.infoq.com/article...
改编自: http://www.infoq.com/cn/artic...

demo code : https://github.com/1000copy/s...


Reco
4.6k 声望541 粉丝

敢作敢为


引用和评论

0 条评论