Rest服务的健壮性考虑

之前写了个六步实现Rest风格的API,详述了怎么开发Rest风格的服务。Rest是基于HTTP的,有必要知道,HTTP是一个简单的基于“请求/响应”的协议,它初始时候只是设计用来获取静态的或动态生产的内容。HTTP不支持事务,简单的来说,在接受处理完请求像想客户端发送完响应后,HTTP服务器即认为它的工作已经完成了。这个时候网络或者客户端发生了错误,服务器端是完全不知道的。如果客户端决定重试请求,服务器只会将同样的事情再做一遍,有的时候这会造成应用数据的不一致。因此,在开发支持内容更改的Rest服务的时候,需要特别小心。

忽略TCP连接建立的过程,一个HTTP请求的全过程包括:

  1. 客户端组装请求数据,包括HTTP的头,内容等等
  2. 客户端发出请求,向网络发出数据,服务器端接受数据
  3. 服务器将请求解析成自己的数据格式
  4. 服务器端按照请求数据处理请求
  5. 服务器端处理完请求后发送响应回客户端,客户端接受到响应
  6. 客户端解析响应
  7. 客户端做后续业务处理

要保证Rest服务的健壮性,就必须考虑HTTP请求的整个过程。在整个过程的任何一个阶段出现问题的时候,都必须有一个合理的后续处理。


一,客户端组装数据并通过网络发出请求

在这个阶段出现问题是很容易处理的,这个时候请求还没到达服务器。

服务器没有处理请求,也即还没做任何改变数据的操作。客户端一段检测到错误,可以根据错误的原因做下一步处理。如果是组装数据的过程中数据有问题,那中止当前处理即可;如果是通过网络发送数据的时候有问题,比如连接不到主机或者网络连接中断,那客户端可以根据系统特点选择重试几次请求。

二,服务器解析请求

这个时候,服务器也还没有开始处理数据,所以也还不会对数据产生影响。

这个阶段出错的原因可能多重多样,比如请求数据格式不对,或者服务器的某些组件出问题造成无法继续处理请求,或者服务器出现了某些没有预料到的异常。但总的来说,错误应该分为两类:一类是客户端应该重试的,一类是客户端不该重试的。假如服务器突然发生了一个没预料到的异常,比如到数据库的连接突然中断,这个时候客户端重试请求有很大可能会成功;而如果服务器发现客户端发送过来的数据不符合规范,那可以直接要求客户端解决问题后在发送重试。更好的分类方法是按照HTTP协议关于响应码http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html的定义,将错误分类,服务器不需要告诉客户端怎么处理,客户端应该根据自己的需要选择重试还是直接中断。比如服务器返回400,那基本可以认为是客户端请求不符合要求,客户端应该解决问题后在重试;服务器返回500,那有可能是服务器发生了一个未预料的异常,客户端可以选择重试一次请求。

三,服务器端处理请求

这一阶段其实和"服务器解析请求,准备处理数据"阶段类似。不同点是这一阶段可以已经开始处理数据并在处理过程中出现问题。

解决方法就是,服务器应该保证,一旦开始修改数据,那就必须是完全的修改,或者是完全的不修改。说白了就是,服务器应该保证请求的处理应该在单一的完整的事务中。所以如果这个阶段出现问题,事务回滚后,服务器的状态就和"服务器解析请求,准备处理数据"阶段一样了,皆可按"服务器解析请求,准备处理数据"阶段的处理方式处理。

四,服务器端发送响应回客户端,客户端接受响应

服务器如果成功的处理了请求并提交了数据,这个时候服务器已经完全的接受并处理了请求,差的只是将处理的结果告诉客户端。

这个阶段的问题有两种:一种是服务器在组装返回数据的时候出现了异常;另外一种是服务器在通过网络向客户端发送数据的时候网络出现异常。

如果一个请求处理到了这个阶段,不管是那种问题,这个时候出现的任何问题应该都和客户端无关了。服务器既然已经接受并处理了请求,那说明客户端发来的请求是正确的,如果服务器在准备返回结果的时候出错,要么是服务器的bug,要么是服务器出现异常。忽略bug的情况,如果服务器出现异常,那么这个时候服务器应该返回给客户端一个特殊的标示(比如一个特别的响应吗),代表已经处理请求。

服务器在发送数据给客户端的时候出问题是整个系统里最难处理的部分,因为客户端只知道网络出问题,但是完全不知道服务器对请求处理结果如何。如果服务器没处理这个请求的话,客户端重试请求,服务器会再将错误发送给客户端一次,这通常没大问题;但是如果服务器已经处理了第一次的请求,客户端重试就会造成同样的请求被处理了两次。为了确保服务器即便对同一个请求处理了多次也不影响数据一致,服务器必须保证HTTP方法的“幂等”,简单的说就是,任何一个Rest请求都是可以重复请求多次的,如果不出现异常,服务器处理完一次的结果和处理完多次的结果应该是一样的。我们可以利用Rest服务资源都有一个ID的原则处理这个问题,在客户端的任何请求(包括创建)里都必须附上请求资源的ID,服务器每次处理的时候都是处理对应ID的那条数据,这样任何一个资源的最终状态必定是最后一个请求的结果,如果一个请求被重复多次处理,也不会产生数据的不一致。特别指出,创建一条资源的时候也要附上ID(ID可以客户端生成或者服务器提供接口生成),不然的话,服务器必然会产生两条一样的数据。

五,客户端解析响应并做后续业务处理

这个阶段和“客户端组装数据并通过网络发出请求”类似,其实它已经和服务器没太大关系了。服务器如果完全发送了响应,但是客户端解析不正确,多是服务器和客户端不一致造成;如果认为是服务器响应的问题,有了前一步我们讨论的保证,再重试一次也是可以的。


参考资料:http://hc.apache.org/httpclient-3.x/exception-handling.html#Transport%20exceptions


关键字: REST,健壮性,robust


 版权所有,转载请注明来源





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值