1. 程式人生 > >RPC和REST的區別

RPC和REST的區別

最近在參加論壇和微信群裡還是看到很多人討論這個問題,其實最重要的還是大家對究竟什麼是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解決的是不同層次的問題