由于服务端使用标准文本形式的响应,所以客户端可以很灵活地对资源进行使用,而基于 HTTP的REST能够提供多种不同的响应形式。到目前为止我们看到的例子都是XML的, 但事实上目前JSON更加流行。
JSON无论从形式上还是从使用方法上来说都更简单。有些支持者认为,相比XML, JSON的内容更加紧凑,这为选用JSON增加了砝码,虽然真实世界中这并不是太重要的 问题。
但是JSON也有一些缺点。XML使用链接来进行超媒体控制。JSON标准中并没有类似的 东西,所以出现了很多不同的自定义的方式在JSON中进行超媒体控制。HAL (Hypertext Application Language,超文本应用语言,http://stateless.co/hal_specificadon.html)试图为 JSON (也包括XML,虽然大家普遍认为XML不需要它的帮助)定义通用的超文本标准 格式。如果你遵守HAL的标准,就可以使用基于Web的HAL游览器来使用超媒体控制, 这会使创建客户端简单得多。
当然并不是说只有这两种格式。通过HTTP我们可以发送任何格式,甚至是二进制的。我 看到越来越多的人直接使用HTML,而非XML。对于有些接口来说,HTML既可以做 UI,也可以做API,当然这么做是很容易出错的,因为与人类之间的交互,和与计算机之 间的交互的差异是很大的。当然这确实是一个很有吸引力的想法,毕竟已经有那么多现成 的HTML解析器可用。
不过我个人来讲还是很喜欢XML的,因为在工具上有很好的支持。举个例子,如果我只 想提取负载(在4.13节讨论“版本化”时会再讨论该技术)中某个特定部分的话,可以使 用XPATH,而支持XPATH标准的工具相当多。CSS选择器也可以,并且用起来还更简 单。使用JS0N的话,也有JSONPATH可用,佴是目前支持该标准的工具很有限。我感觉 很奇怪的是,很多人选择JSON是因为它很轻量,但是又想方设法把超媒体控制之类的概 念添加进去,而这些概念是在XML中早已存在的。不过我承认我可能是少数派,大多数 人还是喜欢使用JSON。
4.7.4留心过多的约定
由于REST越来越流行,帮助我们构建RESTFul Web服务的框架也随之流行起来。然而有 些工具会为了短期利益而牺牲长期利益,为了让你一开始启动得足够快,它们会使用一些 不好的实践。举个例子,有些框架可以很容易地表示数据库对象,并把它们反序列化成进 程内的对象,然后直接暴露给外部。我记得在一个会议上看到有人使用Spring Boot演示厂 这种做法,并a宣称这是它们的主要优势。这种方式内在的耦合性所带来的痛苦会远远大 于从一开始就消除概念之间的耦合所需要的代价。
我们很容易把存储的数据直接暴露给消费者,那么如何避免这个问题呢?在我的团队中一 个很有效的模式是先设计外部接口,等到外部接口稳定之后再实现微服务内部的数椐持久 化。在此期间,简单地将实体持久化到本地磁盘的文件上,当然这并非长久之计。这样做 可以保证服务的接口是由消费者的需求驱动出来的,从而避免数据存储方式对外部接口的 影响。其缺点是推迟了数据存储部分的集成。我认为对干新的服务来说,这个取舍是可接 受的。 .
4.7.5基于HTTP的REST的缺点
从易ffl性角度来看,基于HTTP的REST无法帮助你生成客户端的桩代码,而RPC可以。 没错,使用HTTP意味孴有许多很棒的HTTP客户端库可供使用,但是如果你想要在客户 端中实现并使用超媒体控制的话,那基本上就要靠自己了。从个人ft度来讲,我认为客户 端的库可以做得更好,当然现在的库已经比过去的好很多了。但是我发现使用库会增加复 杂度,因为人们会不自觉地回到基于HTTP的RPC的思路上去,然后构建出一些共¥库。 在客户端和服务器之间共享代码是非常危险的,4.11节会就此做更多讨论。
还有一个小问题:有些Web框架无法很好地支持所有的HTTP动同。这就意味着你很容 易处理GET和POST请求,但是PUT和DELETE就很麻烦了。像Jersey这样比较好的 REST框架就不存在这个问题,但如果在框架选择上有所限制的iS,你可能就无法完整地 使用REST风格了。
性能上也可能会遇到问题。基于HTTP的REST支持不同的格式,比如JSON或者二进制, 所以负载相对SOAP来说更加紧凑,当然和像Thrift这样的二进制协议是没法比的。在要 求低延迟的场景下,每个HTTP请求的封装开销可能是个问题。
虽然HTTP可以用于大流量的通信场景,似对低延迟通信来说并不是最好的选择。相比之 下,有一些构建于TCP (Transmission Control Protocol,传输控制I协议)或者其他网络技 术之上的协议更加高效。比如WebSockets,虽然名字中有Web,但其实它基本上跟Web 没什么关系。在初始的HTTP握手之后,客户端和服务端之间就仅仅通过TCP连接了。对于向浏览器传输数据这个场景而言,WebSockets更加高效。如果这是你的需求的话,那么 注意你其实并不需要使用很多HTTP的特性,更别说其他跟REST相关的东西了。
对于服务和服务之间的通信来说,如果低延迟或者较小的消息尺寸对你来说很重要的话, 那么一般来讲HTTP不是一个好主意。你可能需要选择一个不同的底层协议,比如UDP (User Datagram ProtocoK用户数据报协议)来满足你的性能要求。很多RPC框架都可以
很好地运行在除了 TCP之外的其他网络协议上。
有些RPC的实现支持高级的序列化和反序列化机制,然而对于REST而言,这部分工作 就要自己做了。这部分工作可能会成为服务端和客户端之间的一个耦合点,因为实现一个 具有容错性的读取器不是一件容易的事情(后面会做讨论),但是从快速启动的角度来看,
它们还是非常有吸引力的。
尽管有这些缺点,在选择服务之间的交互方式时,基干HTTP的REST仍然是一个比较合 理的默认选择。如果想了解更多,我建议你阅读《REST实战》这本书,该书对REST做 了非常详细的介绍。