[翻译作品]2008年8月《REST反模式》

全文于2008年8月4日发布于InfoQ中文站上:http://www.infoq.com/cn/articles/rest-anti-patterns 并转载于2008年9月出版的《程序员》杂志上:http://blog.csdn.net/programmer_editor/archive/2008/08/26/2831730.aspx 摘要 人们在试验REST时,通常会四处寻找样例——而他们往往不仅能找到一大堆自称“符合REST”或标榜为“REST API”的样例,还会发现许多关于某个自称符合REST的特定服务名不副实的讨论。 为什么会这样?HTTP虽不是什么新事物,但人们使用它的方式却五花八门。其中有些做法符合Web设计者的初衷,但许多并非如此。要为你的HTTP应用(无论是面向人类、还是计算机、或同时面向这两者使用的)应用REST原则,意味着你要恰好反过来:尽量“正确地”使用Web,或者说按符合REST的方式使用Web(倘若你不喜欢用对或错来评判的话)。对许多人来说,这的确是一种崭新的方式方法。 我经常在文章里作同样的声明:REST、Web和HTTP是不同的事物;REST可以用多种不同技术来实现,而HTTP只是一种恰好符合REST架构风格的具体架构。所以,其实我应该小心区分“REST”与“REST式HTTP”这两个概念的。但我没有这么做,在本文剩余部分,我们姑且认为它们是相同的事物。 跟任何新的方式方法一样,发掘一些共同的模式是有益的。在本系列的第一和第二篇文章中,我已经讲述了一些基础——比如集合资源的概念、将计算结果转换为资源本身、以及用聚合(syndication)来模仿事件。后续文章将进一步讲述这些及其他模式。不过在本文中,我想主要说说反模式(anti-patterns)——即那些力求符合REST式HTTP、但未能成功而造成问题的典型做法。 首先我们来看看我发掘了哪些反模式: 全部采用GET 全部采用POST 忽视缓存 忽视响应代码 误用cookies 忘记超媒体 忽视MIME类型 破坏自描述性 下面我们来逐个详细说明。 全部采用GET 在许多人看来,REST仅仅意味着用HTTP暴露一些应用功能。HTTP GET是最重要的基本操作(operation )(严格地讲,用“动词(verb)”或“方法(method)”这样的术语比较好)。GET方法应当用于获取由URI标识的资源的一个表示(representation),而许多(即便谈不上所有)现有的HTTP库和服务器编程API不是将URI视为一种资源标识符(resource identifier),而是将之视为一种传递参数的便利手段。这导致了以下这种URIs的出现:http://example.com/some-api?method=deleteCustomer&id=1234 <略> 全部采用POST 这一反模式跟前一个颇为相似,只不过这里用的是POST方法而已。POST除了携带一个URI,还携带一个实体主体(entity body)。一个典型的场景是:将单个URI作为POST请求的目标、通过发送不同的消息来表达不同的意图。实际上,SOAP 1.1 Web服务就是这样做的,它把HTTP当作一种“传输协议”来用。服务器根据SOAP消息(可能还包括一些WS-Addressing SOAP报头)决定做什么。 <略> 忽视缓存 即使你按各个动词的原本意图来使用它们,你仍可以轻易禁止缓存机制。最简单的做法就是在你的HTTP响应里增加这样一个报头: Cache-control: no-cache 这样可以禁止缓存机制发挥作用。当然,这也许正是你想要做的,然而通常这只是你的Web框架规定的一个缺省设置。不过,对高效的缓存与再验证(caching and re-validation)的支持,是采用REST式HTTP的诸多关键优点之一。Sam Ruby表示,在判断是否符合REST原则时的一个关键问题就是“你支持ETag吗”?(ETag是HTTP 1.1里引入的一种机制,它允许客户端通过加密的校验和来验证一个被缓存的表示是否仍然有效)。要生成正确的报头,最简单的做法就是把这个任务交给一个“ 知道”怎样做的基础设施——例如通过在Web服务器(比如Apache HTTPD)的目录里生成一个文件。 <略> 忽视响应代码 HTTP提供了一组丰富的应用级状态代码,它们可用于应付不同场合,不过许多Web开发者对此并不知晓。大部分人对200(“OK”)、404(“Not found”)和500(“Internal server error”)这些状态代码是比较熟悉的。但除此以外还有很多其他状态代码,正确使用这些状态代码意味着客户端与服务器可以在一个具备较丰富语义的层次上进行沟通。 <略> 误用cookies 利用cookies来传播某个服务端会话状态的键(key)是另一种REST反模式。 Cookies表明肯定哪个地方不符合REST了。是这样吗?不;不一定。REST的关键思想之一是无状态性(statelessness)——不是说一个服务器不能保存任何数据:倘若是资源状态(resource state)或客户端状态(client state),那是可以的。服务器不能保存的是会话状态(session state),因为那会造成可伸缩性、可靠性及耦合方面的问题。Cookies的最典型的用法是:保存一个跟“某个保存在服务端内存里的数据结构”相关联的键(key)。这意味着,浏览器随各次请求发出去的cookie是被用于构建会话状态的。 <略> 忘记超媒体 最不易接受的REST思想就是标准的方法集合。REST理论并没有规定标准集合由哪些方法组成,它只是规定必须有一组适用于所有资源的方法集合。对于 HTTP来说,这组集合是GET、PUT、POST和DELETE(至少起初是这样),你需要一定适应时间才能掌握如何将所有应用语义投射到这四个动词上。但你一旦适应了,就可以开始运用这个REST的子集——一种基于Web的CRUD(Create、Read、Update、 Delete)架构——了。暴露这种反模式的应用不是真正的“非REST式”应用(假如存在这种事物的话),它们只是未能利用一个REST核心概念——“ 超媒体即应用状态引擎(hypermedia as the engine of application state)”。 <略> 忽视MIME类型 HTTP有个内容协商(content negotiation)的概念,它允许客户端根据需要获取资源的不同表示(representations)。例如,一个资源也许有不同格式的表示(如 XML、JSON或YAML等)以便于用各种不同语言(如Java、JavaScript及Ruby)实现的消费者所使用。再如,一个资源可能即有面向人类的PDF或JPEG版表示,又有“机器可读的”XML版表示。还有,一个资源可能同时支持v1.1版和v1.2版的自定义表示格式。不管怎样,也许可以为“只有一个表示格式”找到理由,但这常常意味着丢掉某种机会。 <略> 破坏自描述性 这种反模式是如此普遍,以至于几乎在每个、甚至那些由所谓的“REST狂热者们”(包括我在内)创建的REST应用里都可以看到:违反自描述性约束(这一努力目标并不像人们最初想象的那样跟人工智能科幻小说有多大牵连)。理想情况下,一个消息(HTTP 请求或HTTP响应,包括报头与主体)应该包含足够信息,以便任何通用客户端、服务器或媒介(intermediary)能够处理它。例如,当你的浏览器获取某个受保护资源的PDF表示(representation)时,你可以看到由标准达成的协定是如何起作用的:有些HTTP认证交换发生,可能会发生一些缓存(caching)和/或再验证(revalidation),服务器发送的content-type报头(application/pdf)触发了你系统里注册的PDF阅读器,最后你得以在自己的屏幕上阅读该PDF。所有用户都可以用他们自己的基础设施来执行同样的请求。若服务器开发者另外增加一种内容类型,那么服务器的客户端(或服务的消费者)只需确保他们安装了正确的阅读器即可。 <略> 总结 自从“四人组(Gang of Four)”出版了书籍、掀起模式运动的开端以来,许多人误解了它,并试图在尽可能多的场合下应用模式——这已被其他人所取笑。模式应当仅在符合上下文时才被应用。同样地,可能有人会不遗余力地在所有场合下虔诚地努力避免所有反模式。许多时候,你有充分理由违反某一规则,或者按REST的术语放松某一约束。这么做是没问题的——但了解实际情况、作出知情决策是有益的。 但愿本文能有助于你在开始首个REST项目时避免落入这些常见的陷阱。 非常感谢Javier Botana和Burkhard Neppert对本文初稿的反馈。




发表评论:
昵称:
密码:
主页:
标题:
验证码:  (不区分大小写,请仔细填写,输错需重写评论内容!)

日历 | CALENDAR

«July 2025»
12345
6789101112
13141516171819
20212223242526
2728293031
blog名称:World Wide Web Watch
日志总数:193
评论数量:665
留言数量:75
访问次数:6081428
建立时间:2004年10月30日
站点首页 | 联系我们 | 博客注册 | 博客登陆

Sponsored By W3CHINA
W3CHINA Blog 0.8 Processed in 0.047 second(s), page refreshed 144751640 times.
《全国人大常委会关于维护互联网安全的决定》  《计算机信息网络国际联网安全保护管理办法》
苏ICP备05006046号