最近在参加论坛和微信群里还是看到很多人讨论这个问题,其实最重要的还是大家对究竟什么是RPC和什么是REST的理解有误
RPC
什么是RPC,在浏览器通过js访问http地址调用了后台接口是RPC吗?tcp通信协议里客户端向服务器发送了一个二进制消息触发了服务器某个函数的执行,这是RPC吗?维基百科对RPC的定义如下:
远程过程调用(英语:Remote Procedure Call,缩写为 RPC)是一个计算机通信协议。该协议允许运行于一台计算机的程序调用另一台计算机的子程序,而程序员无需额外地为这个交互作用编程。
参考这个定义上述两种情况貌似可以归为RPC,但其实定义中的最一句话非常重要,应该被重点说明:
而程序员无需额外地为这个交互作用编程
JS访问HTTP需要处理http协议的细节,tcp发送二进制消息更要处理socket的链接中断各种情况,也就是程序员需要为处理这些交互作用编程,所以它们不属于RPC。
RPC的一个典型特点是有一个stub(存根)程序,一般是通过服务器的接口生成stub,然后直接给客户端使用,客户端在代码中直接引入这个stub(在C++里是一个头文件,在java里是一个interface接口),然后客户端直接就能调用这个函数。
参考这个示例:
代码链接
服务器代码
import java.rmi.RemoteException;
import java.rmi.server.UnicastRemoteObject;
// 服务实现
public class ServiceImpl extends UnicastRemoteObject implements IService {
/**
*/
private static final long serialVersionUID = 682805210518738166L;
/**
* @throws RemoteException
*/
protected ServiceImpl() throws RemoteException {
super();
}
/* (non-Javadoc)
*
*/
@Override
public String queryName(String no) throws RemoteException {
// 方法的具体实现
System.out.println("hello" + no);
return String.valueOf(System.currentTimeMillis());
}
}
STUB程序:
public interface IService extends Remote {
public String queryName(String no) throws RemoteException;
}
客户端:
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
// RMI客户端
public class Client {
public static void main(String[] args) {
// 注册管理器
Registry registry = null;
try {
// 获取服务注册管理器
registry = LocateRegistry.getRegistry("127.0.0.1",8088);
// 列出所有注册的服务
String[] list = registry.list();
for(String s : list){
System.out.println(s);
}
} catch (RemoteException e) {
}
try {
// 根据命名获取服务
IService server = (IService) registry.lookup("vince");
// 调用远程方法
String result = server.queryName("ha ha ha ha");
// 输出调用结果
System.out.println("result from remote : " + result);
} catch (AccessException e) {
} catch (RemoteException e) {
} catch (NotBoundException e) {
}
}
}
可以看到客户端直接调用stub函数就可以,就跟调用本地函数一样,这也是符合各个文章上介绍的RPC定义和特征
String result = server.queryName("ha ha ha ha");
REST
REST大家已经都有接触,这里我重点说两个误区:
访问链接动态生成
普通的web程序由服务器和客户端约定好url路径和作用,比如 http://test/class 对应班级,http://test/class/1/students 对应班级1下的学生。而REST仅仅约定一个入口URL,其他都由服务器生成后发送给客户端。比如当客户端访问http://test/class/1时,服务器会通过json数据告诉客户端班级1下的学生列表对应url为 http://test/class/1/students ,如果服务器不将该url告知客户端那么该客户端将无法访问students列表信息。这即REST定义里提到的由服务器控制资源的状态转移。
HTTP VERBOSE
HTTP verbose 的put get delete post并非一定要对应数据库的增删改查,REST并没有这种要求。
区别
从这里即可看到REST和RPC无法对比。RPC的是本地程序和远程程序交互的一种方式。而REST是一种架构风格,用来约定客户端和服务器之间的接口如何定义。在开发中如果要实现完整的交互,我们即需要定义接口的格式,也需要定义双方的交互方式。比如在C++程序中我们要定义二进制格式的协议(即接口格式),也要决定选择哪个通信协议(TCP或者UDP等)。所以rest和rpc解决的是不同层次的问题