写点什么

REST 服务开发实战

2011 年 2 月 22 日

REST 介绍

如果要说什么是 REST 的话,那最好先从 Web(万维网)说起。

什么是 Web 呢?读者可以查看维基百科的词条 ( http://zh.wikipedia.org/zh-cn/Web ),具体的我就不多说了。总之,Web 是我们在互联网上最常用的服务,甚至在某些人的心中,互联网就是 Web。当然,Web 只是互联网的一部分而已,只是大家用的最多而已,我们访问的所有网站都是基于 Web。

那么,Web 和 REST 之间究竟有什么关系呢?我们接下来将聊聊组成 Web 的几大基础技术, URI (统一资源标识符,用来标识资源)、 HTTP (超文本传输 / 转移协议,用来操作资源)、 Hypertext (超文本,用来描述资源的内容与状态,我们可以用 HTML、XML、JSON 或者自定义格式的文本来描述任何一个资源)。

那我们再来看看什么是 REST 呢?其实 REST 并不是一种新兴的技术语言,也不是什么新的技术框架。准确来说说 REST 只是一种概念、风格或者约束,是回归 HTTP 本身的建议。

REST 是由 Roy Thomas Fieding 在他的博士论文《Architectural Styles and the Design of Network-based Software Architectures》(《架构风格与基于网络的软件架构设计》) 中提出的一种架构思想。Roy Fielding 是 Apache 基金会的合作创作者,同时也是 HTTP、URI 等 Web 基础协议的主要设计者。从 Roy Fielding 的背景,我想大家就应该能了解到 REST 与 Web 之间的关系了吧。的确,在 REST 中我们关注技术实际上也只是 URI、HTTP、Hypertext 而已。

Roy 在他的论文中提出了一个 RESTful 应用应该具备的几点约束。

  • 每个资源都应该有一个唯一的标识
  • 使用标准的方法来更改资源的状态
  • Request 和 Response 的自描述
  • 资源多重表述
  • 无状态的服务

Roy 认为,只有具备了上面的约束的应用才能算是 REST 应用,其实现在许多所谓的 REST 应用或服务,其实并不能算是真正的 REST 应用。

我发现,目前很多所谓的 REST 应用,其实只是 RPC 而已。出现这样的情况很正常,因为 RPC 更符合一般程序员的思维。可是,REST 和 RPC 之间还是有很大的差异的,下面我们说一说 REST 和 RPC 之间的区别。

  • REST 强调资源有唯一的 URI;而 RPC 更加强大过程(动词),由统一的接口来调用它们。
  • REST 回归 HTTP 最初的设计;RPC 仅仅只是把 HTTP 作为传输协议来使用。
  • REST 是由超文本驱动的;RPC 是由方法驱动的。
  • REST 强调 HTTP 通信的语义可见性,通过消息头和标准的 HTTP 方法来体现;RPC 把语义封装在 HTTP 消息体中。

REST 的应用场景

通过上面的介绍,大家应该对 REST 有一些最基本的了解,由于 REST 应用的这些约束,我们可以很轻易地了解和使用 REST 的服务(只要你了解 HTTP)。

其实,我们经常容易犯的一个错误是:当我们了解了一个新的技术,就会用这个技术来解决所有的问题。有一句谚语是这么来说的:“在锤子的眼里,所有的东西都是钉子”,其实 REST 也只是我们工具箱里面的其中的一个工具而已,希望不要把它当做我们唯一的工具。下面,我们就来聊聊适合使用 REST 的应用场景和不适合使用 REST 的应用场景。

在我看来,REST 最适合的应用场景是需要对外暴露服务的情况。此时,我们可以充分利用 REST 的自描述、无状态、唯一标识等特性来提供清晰、友好的 API;此外,目前 Jesery、RESTEasy 等 JAX-RS 框架也提供了 OAuth 的支持,基本上能够保证服务安全。

最不适合的应用场景是对性能要求高的系统内部的服务调用,在这种情况下使用 REST 的话,那么 REST 所有的特性都会变成拖累。这个时候,还是需要选择更底层的通信协议和方式会更好一些,比如 ICE。这样的错误,我曾经犯过,后来通过很长时间的努力才慢慢的将这个错误改过来。

规划 REST 服务

当我们要规划 REST 服务的时候,其中最关键的概念是“资源”。

资源是什么呢?广义上讲,任何事物只要有用,它就是资源。狭义的讲(在 Web 环境中),它是一个可以存放、连接在计算机上,可以通过比特流进行操控的实体。一个实体若要成为资源,它必须有一个 URI。在这里 URI 包含了两重含义:1) 它是该资源的名称 2) 它是该资源的地址。

在规划 URI 的时候,有几点希望大家能够注意一下:

  • 一个 URI 标识一个资源,但是一个资源可以被多个 URI 标识。
  • 资源也是有层次的,这个层次应该在 URI 上充分的体现出来。
  • 在规划 URI 的时候,需要定义一些团队内部确认的关键字或符号,这些关键字或符号是有特殊意义的,不能随便使用。
  • 需要有一个 URI 定义的文档,以备以后的查询和维护。
  • 可以使用 URI Template 来描述 URI 的定义。如何使用 URI Template 请看看这篇文章

当我们定义好资源之后,接下来要做的事情就是定义操作资源的方法以及资源的表述格式了。

使用 HTTP 提供的基本方法来对资源进行操作,一般的操作定义如下:POST(创建资源)、GET(获取资源)、PUT(修改资源)、DELETE(删除)。它们正好对应了 CRUD。

对资源的表述,一般的选择会是 XML,但是我更加推荐使用 JSON 来表述资源。在网络中的传输量小,而且也便于 JavaScript 解析,同时使用其他语言解析也是非常方便的事情。不过,最关键的还是占用更少的资源,让同样的资源能够服务于更多的人。

下面的这张图就很好地说明了 REST 中最重要的围绕资源的三角关系。

在 InfoQ 上有一篇很好的文章来介绍如何规划 REST 服务《如何获取(GET)一杯咖啡——星巴克REST 案例分析》,估计大家看完这篇文章,应该对如何规划REST 服务会有更深的认识。

选择一个快速方便的REST 框架

目前,REST 的框架非常多,推荐大家使用Jersey 和RESTEasy 来创建自己的REST 服务。

这两个框架都出自名门,Jersey 是由SUN 提供的JAX-RS 实现参考,对JAX-RS 支持的最为充分和快速,基本上所有的JAX-RS 的新特性都会在Jersey 里第一个体现出来,而且提供了相当齐备的例子让你学习。RESTEasy 则是JBoss 开源的项目,它同样有很多优点,文档也比Jersey 更好一些,但是它和JBoss 应用服务器绑定的比较紧密,这点我个人不太喜欢,如果你是熟悉JBoss 应用服务器的人,那就选择RESTEasy,它给人的感觉是更加成熟一些,不像Jersey 那样频繁地加入新特性。说到底,还是需要根据个人自己的喜好来选择。

如何使用Jersey 来快速创建REST 应用?参见通过Jersey 快速构建REST 应用;如何使用RESTEasy 快速创建REST 应用?参见使用RESTEasy 快速创建REST 应用

发布REST 服务需要注意的地方

之前,我提到了使用REST 的最佳的场景是对外提供公开的服务,也就是所谓的OpenAPI。一旦开放了API,我们就很难控制这些API 的使用及其调整了,如果在开放这些API 之前考虑的不周到的话,那么后期的维护就会是一个非常麻烦的事情了。所以,当我们决定要开放API 的时候,我们一定要注意一些事情,下面的这些算是我的经验总结。

对外暴露API 时,需要注意版本规划,以便以后API 的升级和维护。在开始开放API 的之前,API 的版本规划是一件很容易被忽视的工作。但是一旦你的API 开放之后,你就会发现,没有对开放的API 进行版本规划,是一件非常愚蠢的事情。当使用你的API 的人越来越多,当你的开放的API 越来越多,一旦某个API 要升级,输入和输出发生变化的时候,你更不知道该通知谁来升级,解决问题的时候同样非常麻烦。

另外,由于对外暴露API 之后,你很难控制API 被调用的次数和意图,所以需要在一些关键的API 被调用的次数和频率上进行控制,以免受到恶意攻击。但是,访问次数和频率应该控制在怎样的程度,就要看你的API 的重要程度以及负载能力了,每个系统都会有自己的评判,只要你掌握好了这个尺度,应该都不会有问题的。

另外,由于当前浏览器的限制,只能使用HTTP 的GET 和POST 方法,如果通过AJAX 直接调用REST 服务,当你的服务中需要使用HTTP 的PUT 或者DELETE 方法调用服务时,最好应考虑使用重载POST 的方式,将需要使用PUT 和DELETE 方法调用的服务通过POST 方法调用。

关于作者

邓涛(Tony Deng),目前从事移动互联网领域,关注高性能、高并发的互联网架构。


感谢马国耀对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。

2011 年 2 月 22 日 00:0013977

评论

发布
暂无评论
发现更多内容

敏捷里为何倡导固定迭代周期?

万事ONES

敏捷开发 研发管理 迭代

公安指挥中心大屏可视化系统开发,情报研判分析平台建设

WX13823153201

自动量化搬砖套利交易机器人系统软件APP开发

开發I852946OIIO

系统开发

Volcano架构设计与原理介绍

华为云原生团队

大数据 AI 云原生 高性能 批量计算

区块链十年与传统金融的变化

CECBC区块链专委会

区块链 金融

区块链科普系列:区块链是什么?

CECBC区块链专委会

区块链

古有诸葛亮八卦阵阻敌,今有iptables护网安

华为云开发者社区

安全 防火墙 网络 iptables 数据包

万字多图 | UML 入门指南

白色蜗牛

Java 程序员 架构设计 UML 后端编程

不同公司产品经理岗位对比

LouisN

架构师训练营W13作业

Geek_f06ede

一文解析DDD中台和微服务设计

欧创新

中台 微服务 领域驱动设计 DDD 微服务划分

用AI「驯服」人类幼崽,手头有娃的可以试试

博文视点Broadview

人工智能 联邦学习 强化学习 集成学习 技术宅

一文带你探究Sentinel的独特初始化

华为云开发者社区

redis sentinel 框架

解决div里面img图片下方有空白的问题

学习委员

CSS html html5 前端 28天写作

Kubernetes概念篇:基本概念和术语

xcbeyond

Kubernetes 容器 pod 28天写作 Kubernetes从入门到精通

架构师训练营第十三周作业

李日盛

PageRank

来不及解释!Linux常用命令大全,先收藏再说

华为云开发者社区

Linux 编程 命令行 命令

生产者与消费者模式,数组阻塞队列(ArrayBlockingQueue)

码农架构

Java 学习 并发编程 架构、

『CDN』让你的网站访问起来更加柔顺丝滑

古时的风筝

CDN

即构小程序直播组件集成教程

ZEGO即构

「产品经理训练营」第一章作业

Sòrγy_じò ぴé

产品经理训练营

4大应用场景,16张高阶布局大屏,最具价值的数据可视化都在这里!

一只数据鲸鱼

物联网 数据可视化 智慧大屏可视化 3D可视化

矿机挖矿APP系统模式开发平台

v16629866266

遇到代码缺陷不要慌,马上教你快速检测和修复

华为云开发者社区

代码 bug 缺陷检测 代码缺陷

DevSecOps安全检查清单

啸天

安全 DevSecOps 应用安全

“反垄断”来袭,对产业区块链有什么启发

CECBC区块链专委会

市场垄断

为什么我认为 Deno 是一个迈向错误方向的 JavaScript 运行时?

hylerrix

typescript rust nodejs deno V8

面试官:你真的了解Redis分布式锁吗?

鄙人薛某

redis 分布式锁 线程安全 RedLock

我在极客时间录课的故事(一):从源码管理聊到一体化学习环境

李艺

我在极客时间录课的故事

第十三周课后练习

晴空万里

架构师训练营第2期

当音乐学博士搞起编程...

程序猿DD

Spring Frame

微服务架构下如何保证事务的一致性

微服务架构下如何保证事务的一致性

REST服务开发实战-InfoQ