两者没有高下之分,无非是一种约定俗成的标准。习惯用 RPC 就用 RPC,能理解 REST 就用 REST。
JSON-RPC 比较符合直观,格式也相对宽松;
REST 最近正流行,有自己的一套设计规范。
REST 面对的疑问跟当年刚开始流行面向对象时的情况是一样的。
它适合很多情况,但并不适合所有情况。
最差的结果就是盲目跟风,又对 REST 的概念和理念一知半解,最后搞出一个半吊子的怪胎,还自我标榜用了流行的 RESTful API。
REST 是一种设计风格,它的很多思维方式与 RPC 是完全冲突的。
RPC 的思想是把本地函数映射到 API,也就是说一个 API 对应的是一个 function,我本地有一个 getAllUsers,远程也能通过某种约定的协议来调用这个 getAllUsers。至于这个协议是 Socket、是 HTTP 还是别的什么并不重要;
RPC 中的主体都是动作,是个动词,表示我要做什么。
而 REST 则不然,它的 URL 主体是资源,是个名词。而且也仅支持 HTTP 协议,规定了使用 HTTP Method 表达本次要做的动作,类型一般也不超过那四五种。这些动作表达了对资源仅有的几种转化方式。
这种设计思路是反程序员直觉的,因为在本地业务代码中仍然是一个个的函数,是动作,但表现在接口形式上则完全是资源的形式。
就像面向对象的「万物皆对象」理论在习惯了纯粹面向过程开发的程序员眼里显得十分别扭一样:我的代码本来就是按顺序、循环、分支这么运行的啊,为啥非得在很明确的结构上封装一层一层的基类子类接口,还要故意给两个函数起同一个名字,调用时才选择用哪一个呢?
使用「万物皆资源」的思想编写实际项目中的 API 接口时,最常见的问题就是「这玩意到底是个什么资源?……………… 算了,我就直接写吧,不管什么风格了」
- 比如,login 和 logout 应该怎么 REST 化?
- 比如,多条件复合搜索在 GET 里写不下怎么办?
- 比如,大量资源的删除难道要写几千个 DELETE?
其实在理解了 REST 后,这些都不是什么无解的难题,只是思维方式要转换一下:
- login 和 logout 其实只是对 session 资源的创建和删除;
- search 本身就是个资源,使用 POST 创建,如果不需持久化,可以直接在 Response 中返回结果,如果需要(如翻页、长期缓存等),直接保存搜索结果并 303 跳转到资源地址就行了;
- id 多到连 url 都写不下的请求,应该创建 task,用 GET 返回 task 状态甚至执行进度;
…… 等等等。
如果只是规定了一种规范,却不理解它表相下面的思维方式,实施中又按照自己的理解随意变动,那结果肯定是混乱不堪的。
当然,API 怎么写是开发者的自由。但如果一个 API 在 url 里放一堆动词、资源设计混乱、各种乱用 HTTP Method 和 Status Code,还自称 RESTful API 的话,那就像你养了一条狗,还管它叫猫一样。
这种混搭产物,不如叫它 REFU 吧。
(Remove Extension From Url:从 url 里去掉文件扩展名)
前面说了半天 REST 的理念和不懂 REST 造成的问题,但是,这并不代表 REST 比 RPC 更「高等」,更不是说不理解 REST 的人是落伍的。
所谓代码风格、接口形式、各种林林总总的格式规定,其实都是为了在团队内部形成共识、防止个人习惯差异引起的混乱。JSON-RPC 当然也是有规范的,但相比 REST 实在宽松太多了。
如果一个开发团队规定必须在 url 里写 action,所有请求都是 POST,可以吗?当然也没问题,只是不要拿出去标榜自己写的是 RESTful API 就行。
规范最终还是为了开发者和软件产品服务的,如果它能带来便利、减少混乱,就值得用;反之,如果带来的麻烦比解决的还多,那就犯不上纯粹跟风追流行了。