网络协议——基于JSON的RESTful接口协议

关于基于 XML 的 SOAP 协议其实使用起来并不简单。对于 SOAP 来讲,无论 XML 中调用的是什么函数,多是通过 HTTP 的 POST 方法发送的。但是咱们原来学 HTTP 的时候,我们知道 HTTP 除了 POST,还有 PUT、DELETE、GET 等方法,这些也可以代表一个个动作,而且基本满足增、删、查、改的需求,比如增是 POST,删是 DELETE,查是 GET,改是 PUT。

传输协议问题

对于 SOAP 来讲,比如我创建一个订单,用 POST,在 XML 里面写明动作是 CreateOrder;删除一个订单,还是用 POST,在 XML 里面写明了动作是 DeleteOrder。其实创建订单完全可以使用 POST 动作,然后在 XML 里面放一个订单的信息就可以了,而删除用 DELETE 动作,然后在 XML 里面放一个订单的 ID 就可以了。

于是上面的那个 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> PNJG </Author>
       <price>100000</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": " PNJG ",
  "price": "10000"
 }
}

协议约定问题

RESTful 可不仅仅是指 API,而是一种架构风格,全称 Representational State Transfer,表述性状态转移

和 SOAP 不一样,REST 不是一种严格规定的标准,它其实是一种设计风格。如果按这种风格进行设计,RESTful 接口和 SOAP 接口都能做到,只不过后面的架构是 REST 倡导的,而 SOAP 相对比较关注前面的接口。

而且由于能够通过 WSDL 生成客户端的 Stub,因而 SOAP 常常被用于类似传统的 RPC 方式,也即调用远端和调用本地是一样的。

然而本地调用和远程跨网络调用毕竟不一样,这里的不一样还不仅仅是因为有网络而导致的客户端和服务端的分离,从而带来的网络性能问题。更重要的问题是,客户端和服务端谁来维护状态。所谓的状态就是对某个数据当前处理到什么程度了。这种模式原来没有问题,是因为客户端和服务端之间的比例没有失衡。因为一般不会同时有太多的客户端同时连上来,所以 NFS 还能把每个客户端的状态都记住。

但是互联网场景下,客户端和服务端就彻底失衡了。那服务端索性就要想了,既然这么多客户端,那大家就分分工吧。服务端就只记录资源的状态,例如文件的状态,报表的状态,库存的状态,而客户端自己维护自己的状态。比如,你访问到哪个目录了啊,报表的哪一页了啊,等等。

这就是服务端的无状态化。这样服务端就可以横向扩展了,一百个人一起服务,不用交接,每个人都能处理。所谓的无状态,其实是服务端维护资源的状态,客户端维护会话的状态。对于服务端来讲,只有资源的状态改变了,客户端才调用 POST、PUT、DELETE 方法来找我;如果资源的状态没变,只是客户端的状态变了,就不用告诉我了,对于我来说都是统一的 GET

虽然这只改进了 GET,但是已经带来了很大的进步。因为对于互联网应用,大多数是读多写少的。只要服务端的资源状态不变,就给了我们缓存的可能。例如可以将状态缓存到接入层,甚至缓存到 CDN 的边缘节点,这都是资源状态不变的好处。

按照这种思路,对于 API 的设计,就慢慢变成了以资源为核心,而非以过程为核心。也就是说,客户端只要告诉服务端你想让资源状态最终变成什么样就可以了,而不用告诉我过程,不用告诉我动作。

还是文件目录的例子。客户端应该访问哪个绝对路径,而非一个动作,我就要进入某个路径。再如,库存的调用,应该查看当前的库存数目,然后减去购买的数量,得到结果的库存数。这个时候应该设置为目标库存数(但是当前库存数要匹配)而非告知减去多少库存

当然按照这种设计模式,无论 RESTful API 还是 SOAP API 都可以将架构实现成无状态的,面向资源的、幂等的、横向扩展的、可缓存的。

但是 SOAP 的 XML 正文中,是可以放任何动作的。例如 XML 里面可以写 < ADD >,< MINUS > 等。这就方便使用 SOAP 的人,将大量的动作放在 API 里面。

RESTful 没这么复杂,也没给客户提供这么多的可能性,正文里的 JSON 基本描述的就是资源的状态,没办法描述动作,而且能够出发的动作只有 CRUD,也即 POST、GET、PUT、DELETE,也就是对于状态的改变。

服务发现问题

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

有个著名的基于 RESTful API 的跨系统调用框架叫 Spring Cloud。在 Spring Cloud 中有一个组件叫 Eureka。

服务分服务提供方,它向 Eureka 做服务注册、续约和下线等操作,注册的主要数据包括服务名、机器 IP、端口号、域名等等。

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

当消费方要调用服务的时候,会从注册中心读出多个服务来,那怎么调用呢?当然是 RESTful 方式了。

Spring Cloud 提供一个 RestTemplate 工具,用于将请求对象转换为 JSON,并发起 Rest 调用,RestTemplate 的调用也是分 POST、PUT、GET、 DELETE 的,当结果返回的时候,根据返回的 JSON 解析成对象。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值