Netflix 或 Twitter 风格的 Web 服务应该使用 REST 还是 SOAP?

我已经实现了两个 REST 服务: Twitter 和 Netflix。这两次,我都很难找到将这些服务作为 REST 而不是 SOAP 公开的决策所涉及的用法和逻辑。我希望有人能告诉我我缺少什么,并解释为什么 REST 被用作这些服务的服务实现。

  1. 实现 REST 服务比实现 SOAP 服务花费的时间长得多。所有现代语言/框架/平台都可以使用工具读取 WSDL 并输出代理类和客户端。实现一个 REST 服务是通过手工完成的,并且通过阅读文档来实现。此外,在实现这两个服务时,由于没有真正的模式或参考文档,因此必须对通过管道返回的内容进行“猜测”。

  2. 为什么要编写返回 XML 的 REST 服务呢?唯一的区别是,在 REST 中,你不知道每个元素/属性表示的类型——你只能靠自己来实现它,而 希望总有一天在你认为永远是 int 的字段中不会出现一个字符串。SOAP 使用 WSDL 定义数据结构,因此这是一个不需要动脑筋的问题。

  3. 我听到过这样的抱怨,即使用 SOAP,您也会有 SOAP 信封的“开销”。在这个时代,我们真的需要担心一堆字节吗?

  4. 我听说过这样一种说法: 使用 REST,只需将 URL 放入浏览器,就可以看到数据。当然,如果您的 REST 服务使用简单的身份验证或不使用身份验证。例如,Netflix 服务使用 OAuth,它要求您在提交请求之前对事物进行签名和编码。

  5. 为什么我们需要一个“可读”的 URL 为每个资源?如果我们使用一个工具来实现服务,我们真的关心实际的 URL 吗?

22485 次浏览

SOAP 是一个 面向对象远程过程调用远程过程调用技术堆栈。它通过在现有协议(HTTP)之上构建新的抽象来工作。

REST 是一种 以文件为导向方法,它只使用现有协议(HTTP)的特性。“ REST”只是一个流行词——它的概念是这样的: 只要像使用 设计的那样使用网络就可以了!

针对编辑提出的问题:

  1. “实现 REST 服务比实现 SOAP 服务花费的时间要长得多。”

    不,不能再这样下去了。如果你要检索的是 已经是一个文件或档案实际上是 快多了。例如,WMS 的 OGC 规范(Web Mapping Service)同时定义了 SOAP 和 REST 协议版本,这就是为什么几乎没有人实现 SOAP 版本的原因——这是因为如果你想获得一个地图,仅仅构建一个 URL 并从该 URL 获取图像字节比将其封装到 SOAP 消息中要容易得多。但是,如果 Web 服务的目的是在域对象模型中传输一些强类型的对象,那么 SOAP 更适合这种用途。

  2. “为什么要编写返回 XML 的 REST 服务呢?”

    是啊,那可能有点傻。但这取决于 XML 是什么。如果在某个地方有一个明确定义的模式,那么就不存在模糊性。例如,您可以将 WSDL URL 视为一种 RESTful Web 服务,用于检索关于 Web 服务的信息。在这种情况下,增加另一个 SOAP 请求的开销是毫无意义的。

    一般来说,当被传输的内容可以被认为是 文件,作为一个单位时,REST 胜出。当内容需要作为 带成员的对象处理时,SOAP 胜出。

  3. ”我听到有人抱怨说,使用 SOAP 时,您会有 SOAP 信封的“开销”。在这个时代,我们真的需要担心一堆字节吗?”

    是的。不是在所有的情况下,但有一些网站的流量很大,它使不同的。使用 SOAP 代替 REST 的 语义差异是否足够大?我表示怀疑。如果您正在执行一个对象远程处理协议,并且字节数有所不同,那么 SOAP 可能无论如何都不适合您——也许您应该使用 CORBA 或 DCOM。

  4. “我听说过这样一种说法: 使用 REST,你只需将 URL 放入浏览器,就可以看到数据。”

    是的,这是一个支持 REST 如果在浏览器中查看数据是有意义的的大论据。例如,对于图像数据,这是一种调试服务的简单方法——只需将 URL 粘贴到浏览器的地址栏中,就可以看到图像的样子。或者,如果返回的数据是 XML 格式的,并且您有一个引用的 XML 样式表,可以在浏览器中呈现成可读的 HTML,那么您可以在一个包中获得语义标记和简单可视化的好处。但是,您是正确的,当使用更复杂的身份验证方案时,这种好处大多消失了。如果你不能 将所有身份验证信息编码到每个 HTTP 请求中,那么我认为它根本不能算作 REST。

  5. “为什么我们需要为每个资源提供一个“可读的”URL?如果我们使用一个工具来实现服务,我们真的关心实际的 URL 吗?”

    看情况吧。为什么我们需要可读的网址为任何资源在网上?您可以阅读 Tim Berners-Lee 的文章 译自: http://www.w3.org/Provider/Style/URI中的基本原理,但是基本上,只要资源在未来仍然有用,该资源的 URI 应该保持不变。

    显然,对于临时资源(比如本文中的“今日货币”链接) ,不需要它,因为如果相应的资源消失了,引用资源的需要就消失了。但是对于更永久性的资源(比如 StackOverflow 问题,或 IMDB 上的电影) ,您希望拥有一个可以永久工作的 URL。在设计 Web 服务时,您需要决定资源本身是否能够比服务更长久,如果是这样,那么 REST 可能是正确的选择。

郑重声明,是的,早在 NetFlix 或 Twitter 出现之前,我就已经在开发网页了。不,我还没有任何需要或机会实现一个客户端到 NetFlix 或 Twitter 的服务。但是,即使他们的服务极其难以使用,这并不意味着他们在服务之上实现的技术是糟糕的——只是这两个实现是糟糕的。

长话短说: REST 和 SOAP 是 只有工具。他们各有优缺点。如果你唯一的工具是一个锤子,那么每个问题看起来像一个钉子。因此,了解这两种工具,并学习如何正确使用它们,然后为每个工作选择正确的工具。

WSDL 和其他文档级协议是多余的。HTTP 协议除了提供文档和表单之外,还支持更丰富的操作集。

REST 的支持者对这种冗余感到不舒服。

诚实的问题值得诚实的回答。但是首先,如果你不认为这个问题本质上是修辞性的,为什么你要把它作为一个 回答另一个问题来使用呢?

总之:

  1. 所有现代语言/框架/平台都可以使用工具读取 WSDL 并输出代理类和客户端。实现 REST 服务是通过阅读文档手工完成的。

    就像浏览器厂商已经反复阅读了 HTML 4.01规范,试图实现一致的浏览体验。你有没有想过,浏览器早在网上银行和堆栈溢出之前就已经发明了,然而,你可以用浏览器来做这些事情。这之所以成为可能,是因为每个人都同意使用 HTML (以及 CSS、 JS、 JPEG 等相关格式)。

    写博客其实并不是什么新鲜事,有人想出了 AtomPub,它允许任何博客软件访问和更新博客中的文章,就像任何浏览器都可以访问任何网页一样。这非常简洁,而且由于协议强加的 RESTful 约束,因此可以正常工作。

    但是对于 Twitter 和 Netflix 来说,“所有现存的微博都应该使用媒体类型的应用程序/tweet”这一说法并没有得到普遍认同,主要是因为微博是如此的新。也许几年后,一些微博客服务就会采用同样的 API,这样 Twitter、 Facebook、 Identica 就可以互相操作了。他们现有的 API 中没有一个接近 RESTful,无论他们声称有多少,所以我并不期望它很快发生。

    此外,在实现这两个服务时,由于没有真正的模式或参考文档,因此必须对通过管道返回的内容进行“猜测”。

    你说的一针见血。REST 是关于分布式和超媒体的,这差不多就是它的全部。浏览器查看从请求中获取的内容,并将其显示给用户。HTML 页面通常会产生更多的 GET 请求,例如 CSS、脚本和图像。图像通常只呈现在屏幕上,执行 JavaScript,等等。每次,浏览器都会执行它的操作,因为它在 <img><style>标记中找到了链接,而响应媒体类型是 image/jpegtext/css

    如果 Twitter 开发了一个基于超媒体的应用程序接口(API) ,那么每次你点击一条 tweet 的链接,它可能都会返回一个 application/tweet,但是客户端永远不应该假设这一点,并且在使用它之前总是要检查它得到了什么。

  2. 为什么要编写返回 XML 的 REST 服务呢?

    这一切都归结为媒体类型。与 HTML 一样,如果您看到一个元素,但您不知道它的实际含义,HTML 规范指示您忽略它们,并处理标记的“主体”(如果有的话)。同样,atom 规范指示您忽略未知元素和外部标记(来自不同的名称空间) ,而 没有处理主体(IIRC)。

    为一般问题域设计媒体类型(如 内容丰富问题域的 超文本标示语言媒体类型)是非常困难的。为非常狭窄的问题领域创建媒体类型可能要容易得多(比如 tweet)。但是,为可扩展性进行设计并指定当客户机(和服务器)看到不符合规范的元素或数据项时应该如何反应总是一个好主意。例如,JPEG 有一个特定于应用程序的记录类型(例如 APP1) ,用于包含各种元数据。

  3. 我听到过这样的抱怨,即使用 SOAP,您也会有 SOAP 信封的“开销”。在这个时代,我们真的需要担心一堆字节吗?

    不,我们没有。REST 绝对不是关于线上的效率,它实际上是交易线上的效率。REST 的效率来自于所有其他约束启用缓存的可能性: Fielding 的论文注意: 不过,这样做的好处是,统一的接口降低了效率,因为信息是以标准化的形式传输的,而不是特定于应用程序需求的形式。REST 接口的设计目的是高效地进行大粒度超媒体数据传输,对 Web 的常见情况进行优化,但是产生的接口对于其他形式的体系结构交互来说并不是最佳的。我不认为 SOAP 信封字节数开销是一个有效的关注点。

  4. 我听说过这样一种说法: 使用 REST,只需将 URL 放入浏览器,就可以看到数据。

    是的,这也是一个无效的论点。不是这样的。即使它确实工作,大多数 狭窄 REST API 使用的媒体类型,浏览器不知道,它仍然不会工作。

    但是,测试基于 HTTP 的 API 的可能性比浏览器多得多,比如命令行实用程序或浏览器扩展,它们允许您控制 HTTP 请求的几乎任何方面,检查响应头并发现可以跟随的链接。但即便如此,这也远不如生成 WSDL 存根和编写一个三行程序来调用函数那么容易。

  5. 为什么我们需要一个“可读”的 URL 为每个资源?如果我们使用一个工具来实现服务,我们真的关心实际的 URL 吗?

    如果你看看网络是如何工作的,我敢肯定人们总的来说很高兴维基百科页面的 URI 是这样的,http://en.wikipedia.org/wiki/Stack_overflow而不是 http://en.wikipedia.org/wiki/?oldid=376349090。但实际上它对 REST 并不重要。尝试获得正确答案的重要事情是选择在 URI 中放置不太可能更改的相关数据。您可能认为数据库 ID 永远不会改变,但是当两个数据集需要合并时会发生什么呢?所有的主键都会改变。页面标题(Stack _ overflow)不会更改。

抱歉回答的时间太长,但是我相信这个问题是有效的,并且在此之前没有被处理过。我相信达雷尔 · 米勒回来后也会加上他的回答。

编辑: 格式化

煤矿里的金丝雀。

这样的问题我已经等了快一年了。这一天的到来是不可避免的,我相信在接下来的几个月里,我们将会看到更多类似的问题。

警告信号

您完全正确,构建 RESTful 客户机确实比 SOAP 客户机花费更长的时间。SOAP 工具包带走了大量的样板代码,使客户端代理对象几乎不费吹灰之力就可以使用。使用 Visual Studio 这样的工具和服务器 URL,我可以在5分钟内访问任意复杂度的远程对象。

返回 application/xml 和 application/json 的服务对于客户端开发人员来说非常烦人。我们该怎么处理这些数据?

幸运的是,许多提供 REST 服务的站点还提供了一组客户端库,这样我们就可以使用这些库访问一组强类型对象。不过听起来有点傻。如果他们使用 SOAP,我们可以自己编写代理类的代码。

头顶上的肥皂,哈。潜伏期是致命的。如果人们真的担心过多的字节数通过网络,那么 HTTP 可能不是正确的选择。您是否看到用户代理头使用了多少字节?

是的,你有没有试过用网页浏览器作为除了 HTML 和 javascript 之外的任何东西的调试工具。相信我,糟透了。你只能使用其中的两个动词,缓存不断地成为阻碍,错误处理吞噬了太多的信息,它不断地寻找一个该死的 Favicon.ico。杀了我吧。

可读网址。只有名词,没有动词。是的,这很容易,只要我们只做 CRUD 操作,并且我们只需要以一种方式访问对象的层次结构。不幸的是,大多数应用程序需要比这更多的功能。

即将到来的灾难

目前有大量的开发人员正在开发与 REST 服务集成的应用程序,他们正在得出与您相同的结论。它们被承诺具有简单性、灵活性、可伸缩性、可发展性和偶然重用的圣杯。网络本身的特点,怎么会出问题。

然而,他们发现版本控制同样是一个问题,但是编译器不能帮助检测问题。随着数据结构的发展和 URL 的重构,手写客户机代码的维护非常困难。仅围绕名词和四个动词设计 API 可能非常困难,尤其是 RESTful Url 狂热分子告诉您什么时候可以使用查询字符串,什么时候不能使用查询字符串。

开发人员会开始问,为什么我们要把精力浪费在同时支持 Json 格式和 XML 格式上,为什么不把精力集中在一种格式上,并把它做好呢?

事情怎么会变成这样

我来告诉你哪里出了问题。我们作为开发商,让市场部门利用我们的主要弱点。我们一直在寻找灵丹妙药,却忽视了 REST 的真正含义。从表面上看,REST 似乎很简单。使用 Urls 命名资源,并使用 GET、 PUT、 POST 和 DELETE。见鬼,我们开发人员已经知道如何做到这一点,我们已经处理数据库多年,有表和列和 SQL 语句,有 SELECT,INSERT,UPDATE 和 DELETE。本来应该是小菜一碟的。

有些人讨论 REST 的其他部分,比如自描述性和超媒体约束,但是这些约束并不像资源标识和统一接口那样简单。这似乎增加了复杂性,而期望的目标是简单。

在开发人员文化中,这个被淡化的 REST 版本以多种方式得到了验证。创建了服务器框架,鼓励资源标识和统一接口,但不支持其他约束。术语开始流传,区分不同的方法(HI-REST vs LO-REST,Corporate REST vs Learning REST,REST vs RESTful)。

一些人尖叫着说,如果你不应用所有的约束,它就不是 REST。你不会得到好处的。没有一半的休息。但这些声音被贴上了宗教狂热分子的标签,他们对自己宝贵的词汇被从默默无闻中窃取并成为主流感到不安。嫉妒的人试图使 REST 听起来比实际更难。

REST,这个术语,肯定已经成为主流。几乎所有具有 API 的主要 web 属性都支持“ REST”。Twitter 和 Netflix 是两个非常高调的网站。可怕的是,我只能想到一个自描述的公共 API,而真正实现超媒体约束的只有少数几个。当然有些网站如 StackOverflow 和 Gowalla 在他们的回复中支持链接,但是在他们的链接中有巨大的漏洞。StackOverflow API 没有根页面。想象一下,如果没有网站的主页,网站会有多么成功!

恐怕你被误导了

如果你已经做到了这一点,那么对你的问题的简短回答是那些 API (Netflix 和 Twitter)不符合所有的约束,因此你不会得到 REST APIs 应该带来的好处。

REST 客户机的构建时间确实比 SOAP 客户机长,但是它们并不绑定到一个特定的服务,因此您应该能够跨服务重用它们。举个经典的例子,网页浏览器。一个浏览器可以访问多少个服务?订阅阅读器怎么样?现在,一个普通的 Twitter 客户端能够访问多少种不同的服务呢?是的,就一个。

REST 客户机不应该构建为与单个服务接口,而应该构建为处理可由任何服务提供服务的特定媒体类型。显而易见的问题是,如何为交付 application/json 或 application/xml 的服务构建 REST 客户机。你不能。这是因为这些格式对 REST 客户机完全没用。你自己说的,

你必须“猜”到底是什么 会从管道那边回来 没有真正的模式或引用 文件

对于像 Twitter 这样的服务,你是绝对正确的。然而,REST 中的自描述约束说明 HTTP 内容类型头应该准确地描述通过网络传输的内容。交付 application/json 和 application/xml 不会告诉您任何有关内容的信息。

在考虑基于 REST 的系统的性能时,有必要从更大的角度考虑问题。讨论信封字节就像是在比较快速排序和 shell 排序时讨论循环展开。有些情况下 SOAP 可以执行得更好,有些情况下 REST 可以执行得更好。环境决定一切。

REST 通过灵活处理它支持的媒体类型以及对缓存的复杂支持获得了很大的性能优势。为了使缓存能够很好地工作,尽管必须遵守几乎所有的约束。

您关于可读 URL 的最后一点是最具讽刺意味的。如果您真正提交超媒体约束,那么每个 URL 都可以是一个 GUID,客户端开发人员将不会失去任何可读性。

在开发 REST 系统时,URI 对于客户机来说应该是不透明的,这是最关键的事情之一。可读的 URL 对于服务器开发人员来说很方便,而且结构良好的 URL 使得服务器框架更容易分派请求,但是这些实现细节应该不会对使用 API 的开发人员产生影响。

Twitter API 甚至还没有接近 RESTful,这就是为什么您无法看到通过 SOAP 使用它的任何好处。Netflix API 更为接近,但它对通用媒体类型的使用表明,即使不遵守单个约束,也会对从该服务获得的好处产生深远影响。

也许不全是他们的错

我已经对服务提供商做了很多工作,但是需要两个人才能安静地跳舞。服务可以严格遵守所有约束,而客户端仍然可以轻松地撤销所有好处。

如果客户端硬编码 URL 来访问某些类型的资源,那么它将阻止服务器更改这些 URL。任何基于服务如何构造其 URL 的隐式知识的 URL 构造都是一种冲突。

假设链接将返回什么类型的表示会导致问题。基于 HTTP 头中没有明确说明的知识对表示的内容进行假设肯定会产生耦合,这将在未来造成痛苦。

他们应该使用 SOAP 吗?

我个人不这么认为。正确完成 REST 允许分布式系统长期发展。如果您正在构建分布式系统,其中的组件由不同的人员开发,并且需要持续多年,那么 REST 是一个非常好的选择。

Martin Fowler 有一个 关于理查森成熟度模型的文章,它很好地解释了 SOAP 和 REST 之间的区别。