我们首先说了基于XML的SOAP协议,其中的S是指的是Simple,但是使用起来更不简单

对于SOAP,无论XML中调用的是什么函数,大多是走的是HTTP的POST方法发送的,但是HTTP不仅仅有POST,还有PUT DELETE,GET等方法,正好对应着增删改查

传输协议问题

对SOAP来说,比如创建一个订单,用POST,在XML中写明动作是CreateOrder,删除一个订单,

动作是deleteOrder

于是,上面你的SOAP就是成了下面的样子

POST /purchaseOrder HTTP/1.1

Host: www.geektime.com

Content-Type: application/xml; charset=utf-8

Content-Length: nnn

<?xml version=”1.0″?>

<order>

<date>2018-07-01</date>

<className>趣谈网络协议</className>

<Author>刘超</Author>

<price>68</price>

</order>

XML的格式也可以变成另一种简单的文本化的对象表示格式JSON

POST /purchaseOrder HTTP/1.1

Host: www.geektime.com

Content-Type: application/json; charset=utf-8

Content-Length: nnn

{

“order”: {

“date”: “2018-07-01”,

“className”: “趣谈网络协议”,

“Author”: “刘超”,

“price”: “68”

}

}

对于RESTful来说,不仅仅是指API,而是一种架构风格,全程是Representational Sate Transfer

表述性状态转移,来源于一篇论文 架构风格和基于网络的软件架构设计(Architectural Styles and the Design of Network-based Software Architectures)

和SOAP不同,REST并不是一种严格规定的标准,而是一种设计风格,按照这种风格来设计,RESTful接口和SOAP接口都能做到,只不过把后面的架构是REST倡导的,SOAP相对比较关注前面的接口

而且由于能够通过WSDL生成客户端的Stub,因而SOAP可以被利用与传统的RPC的方式

但是网络调用和本地调用有着很大的区别,不仅仅是客户端和服务端的分离,而且,客户端和服务端,谁来维护状态呢?

比如,我们进行浏览目录,谁来记录我已经浏览到第几页了,本地调用可以不用纠结,但是有了网络调用,就需要考虑这个状态问题

是由客户端来维护,还是服务器端来维护?

比如说,我浏览到了哪个目录了,我看到了第几页了,买个东西,扣减库存,这都是状态,本地调用不需纠结,但是网络调用都需要考虑到

就好比NFS一样,客户端会告诉服务端,我要进入哪个目录,服务端需要维护一个状态,就是这个客户端浏览到哪个目录了,客户端输入了cd hello,服务端要记住,上次浏览到了/root了,这次要前往/root/hello,另外一个客户端,输入了cd hello,服务端也要记住,上次浏览到了/var/lib,这次要进入/var/lib/hello

不光是NFS,如果浏览翻页,我们要实现函数 next(),一个列表中取下一页,但是这就需要服务端记住,客户端A上次浏览到20~30页了,调用next,显示30~40页

上面说的是RPC场景,由服务端来维护状态,很多SOAP接口设计,尝尝按照这个模式,这种模式原本没有问题,通过不会有太多的客户端练上来,所以NFS还可以直接使用

公司内部使用的ERP系统,如果使用SOAP的方式实现,并且服务端为每个登录的用户维护状态,一个公司内部的人不会太多,把ERP放在一个强大的物理机也行

但是,在网络上,比如双十一,这么多人同时购物,记得过来吗?服务端同事提供服务,大家分摊一下,但是如何将状态进行转移呢?

这样,我们理应将服务端维护资源状态,客户端维护会话的状态,对于服务端来说,资源状态改了,客户端才会调用POST,PUT,DELETE.如果资源状态没变,客户端的状态变了,就是简单的GET

这样,就是交给客户端自己维护自己的状态,客户端说,要访问目录下的hello路径,客户端会找到自己之前访问的路径,然后告诉服务端完整的路径,同理,对于分页,也是客户端去维护状态,然后告诉客户端具体的访问页数

这就是服务端的无状态华,服务端可以横向的扩展了,一百个人一起服务,不用对接,每个人都能处理

这样,我甚至就可以将很多资源进行缓存,哪怕是CDN的边缘节点

按照这种思路,互联网发展为了以资源为核心,而非以过程为核心的互联网,服务端只想知道资源会变成什么样

就好比,我们去下一个单,我们需要查看当前的库存路径,然后减去购买的数量,得到结果的库存数,然后设置为目标库存数

这就需要API的幂等性,不能出现无限重试的问题,就是对于同一调用,多次调用的结果应该一样,不能多次调用就运行多次,

按照这种思路,无论是RESTful API还是SOAP API都可以将架构设计为无状态的,面向资源,幂等的,横向扩展,可缓存的

这样,RESTful中没有办法去描述动作,能够发出的动作只有CRUD,对于状态的改变,所以从接口角度,就死了这条心

服务发现问题

对于RESTful API来说,我们已经解决了传输协议的的问题,基于HTTP,协议约定问题,基于JSON,最后解决服务发现的问题

常见的跨系统的调用框架叫做Spring Cloud,其中有一个组件Euerka,负责实现注册中心,负责维护注册的服务列表

服务分服务提供方,向Euerka做服务注册,续约,下线的操作,注册的主要数据包括服务名,机器ip,端口号,域名

另一方是服务消费方,从Eureka获取服务提供方的注册信息为了负载均衡和容错,服务注册方可以注册多个

当消费方要调用服务的时候,会从注册中心读出多个服务出来,然后利用RESTful方式来调用

Spring Cloud提供了一个RestTemplate工具,将请求对象转换为JSON,并且发起REST调用,返回时候,根据返回的JSON解析成对应对象

本章小结

SOAP太过于复杂,而且设计是面向动作的,往往因为架构问题导致并发量上不去

RESTful不仅仅是一个API,而是一种架构模式,主要面向资源,提供无状态的服务,有利于横向扩展

课后思考

1.讨论RESTful模型的时候,举了一个库存的例子,为何这么设计

2.基于文本的RPC虽然解决了二进制的问题,但是本身具有问题的

1.这样,就是将状态进行了转移,将状态交给了存储,这样业务可以无状态华运行,因为无状态,所以可以负载均衡

高并发下,尽管接口支持了幂等性,库存资源修改时需要支持CAS操作

2.基于文本,利于阅读,但不适合大数据交换,二进制压缩率更高,更适合高的吞吐量

发表评论

邮箱地址不会被公开。 必填项已用*标注