JSON-RPC
JSON-RPC,是一個無狀態且輕量級的遠端程序呼叫(RPC)傳送協定,其傳遞內容透過 JSON 為主。相較於一般的 REST 透過網址(如 GET /user
)呼叫遠端伺服器,JSON-RPC 直接在內容中定義了欲呼叫的函式名稱(如 {"method": "getUser"}
),這也令開發者不會陷於該使用 PUT 或者 PATCH 的問題之中。 本規範主要定義了一些資料結構及其相關的處理規則。它允許執行在基於 Socket、HTTP 等諸多不同訊息傳輸環境的同一行程中。其使用 JSON(RFC 4627)作為資料格式。
約定
[編輯]由於 JSON-RPC 使用 JSON,它具有與其相同的型別系統。JSON 可以表示四個基本類型(String、Numbers、Boolean 和 Null)和兩個結構化類型(Objects 和 Array)。任何時候文件涉及 JSON 資料類型,第一個字母都必須大寫:Object、Array、String、Number、Boolean、Null。包括 True 和 False 也要大寫。
在客戶端與任何被匹配到的伺服器端之間交換的所有成員名字應是區分大小寫的。 函式、方法、過程都可以認為是可以互換的。客戶端被定義為請求對象的來源及回應對象的處理程式。伺服器端被定義為回應對象的起源和請求對象的處理程式。
該規範的一種實現為可以輕而易舉的填補這兩個角色,即使是在同一時間,同一客戶端或其他不相同的客戶端。 該規範不涉及複雜層。
相容性
[編輯]JSON-RPC 2.0 的請求對象和回應對象可能無法在較舊的 JSON-RPC 1.0 客戶端或伺服器端正常執行,然而我們可以很容易在兩個版本間區分出 2.0。因為 2.0 版本中必須夾帶一個命名為 jsonrpc 且值為 2.0 的欄位。而 1.0 版本是沒有此欄位的。大部分的 2.0 實現應該考慮嘗試相容或者處理 1.0 的對象,即使不是對等的也應給其相關提示。
請求對象
[編輯]傳送一個請求對象至伺服器端代表一個 RPC 呼叫,一個請求對象包含下列成員:
- jsonrpc
- method
- params
- id
伺服器端必須回答相同的值如果包含在回應對象。這個成員用來兩個對象之間的關聯上下文。在請求對象中不建議使用 NULL 作為 id 值,因為該規範將使用空值認定為未知id的請求。另外,由於JSON-RPC 1.0 的通知使用了空值,這可能引起處理上的混淆。使用小數是不確定性的,因為許多十進制小數不能精準的表達為二進制小數。
通知
[編輯]沒有包含 id 成員的請求對象為通知, 作為通知的請求對象表明客戶端對相應的回應對象並不感興趣,本身也沒有回應對象需要返回給客戶端。伺服器端必須不回覆一個通知,包含那些批次請求中的。
由於通知沒有返回的回應對象,所以通知不確定是否被定義。同樣,客戶端不會意識到任何錯誤(例如參數預設,內部錯誤)。
參數結構
[編輯]RPC 呼叫如果存在參數則必須為基本類型或結構化類型的參數值,要麼為索引陣列,要麼為關聯陣列對象。
- 索引:參數必須為陣列,並包含與伺服器端預期順序一致的參數值。
- 關聯名稱:參數必須為對象,並包含與伺服器端相匹配的參數成員名稱。沒有在預期中的成員名稱可能會引起錯誤。名稱必須完全匹配,包括方法的預期參數名以及大小寫。
回應對象
[編輯]當發起一個 RPC 呼叫時,除通知之外,伺服器端都必須回覆回應。回應表示為一個 JSON 對象,使用以下欄位:
- jsonrpc
- result
- error
- id
回應對象必須包含 result 或 error 欄位,但兩個欄位不能同時存在。
錯誤對象
[編輯]當一個 RPC 呼叫遇到錯誤時,返回的回應對象必須包含錯誤成員參數,並且為帶有下列成員參數的對象:
- code
- message
- data
-32768 至 -32000 為保留的預定義錯誤代碼。在該範圍內的錯誤代碼不能被開發者自己定義,保留下列以供將來使用。錯誤代碼基本與 XML-RPC 建議 (頁面存檔備份,存於網際網路檔案館)的一樣
錯誤碼 | 訊息 | 解釋 |
---|---|---|
-32700 | Parse error - 語法解析錯誤 | 伺服器端接收到無效的 JSON。該錯誤傳送於伺服器嘗試解析 JSON 文字 |
-32600 | Invalid Request - 無效請求 | 傳送的 JSON 內容不是一個有效的請求對象。 |
-32601 | Method not found - 找不到方法 | 該方法不存在或無效。 |
-32602 | Invalid params - 無效的參數 | 無效的方法參數。 |
-32603 | Internal error - 內部錯誤 | JSON-RPC 內部錯誤。 |
-32000 to -32099 | Server error - 伺服器端錯誤 | 預留用於自訂的伺服器錯誤。 |
除此之外剩餘的錯誤類型代碼可供應用程式作為自訂錯誤。
批次呼叫
[編輯]當需要同時傳送多個請求對象時,客戶端可以傳送一個包含所有請求對象的陣列。
當批次呼叫的所有請求對象處理完成時,伺服器端則需要返回一個包含相對應的回應對象陣列。每個回應對象都應對應每個請求對象,除非是通知的請求對象。伺服器端可以並行的,以任意順序和任意寬度的並列性來處理這些批次呼叫。
這些相應的回應對象可以任意順序的包含在返回的陣列中,而客戶端應該是基於各個回應對象中的 id 成員來匹配對應的請求對象。
若批次呼叫的 RPC 操作本身非一個有效 JSON 或一個至少包含一個值的陣列,則伺服器端返回的將單單是一個回應對象而非陣列。若批次呼叫沒有需要返回的回應對象,則伺服器端不需要返回任何結果且必須不能返回一個空陣列給客戶端。
範例
[編輯]在以下的例子裡,-->
表示資料傳送至伺服器,<--
表示資料傳送至使用者端。
帶索引陣列參數的rpc呼叫:
--> {"jsonrpc": "2.0", "method": "subtract", "params": [42, 23], "id": 1}
<-- {"jsonrpc": "2.0", "result": 19, "id": 1}
--> {"jsonrpc": "2.0", "method": "subtract", "params": [23, 42], "id": 2}
<-- {"jsonrpc": "2.0", "result": -19, "id": 2}
帶關聯陣列參數的 RPC 呼叫:
--> {"jsonrpc": "2.0", "method": "subtract", "params": {"subtrahend": 23, "minuend": 42}, "id": 3}
<-- {"jsonrpc": "2.0", "result": 19, "id": 3}
--> {"jsonrpc": "2.0", "method": "subtract", "params": {"minuend": 42, "subtrahend": 23}, "id": 4}
<-- {"jsonrpc": "2.0", "result": 19, "id": 4}
通知:
--> {"jsonrpc": "2.0", "method": "update", "params": [1,2,3,4,5]}
--> {"jsonrpc": "2.0", "method": "foobar"}
不包含呼叫方法的 RPC 呼叫:
--> {"jsonrpc": "2.0", "method": "foobar", "id": "1"}
<-- {"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "1"}
--> {"jsonrpc": "2.0", "method": "foobar", "params": "bar", "baz]
<-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
包含無效請求對象的 RPC 呼叫:
--> {"jsonrpc": "2.0", "method": 1, "params": "bar"}
<-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
--> [
{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
{"jsonrpc": "2.0", "method"
]
<-- {"jsonrpc": "2.0", "error": {"code": -32700, "message": "Parse error"}, "id": null}
包含空陣列的 RPC 呼叫:
--> []
<-- {"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
非空且無效的 RPC 批次呼叫:
--> [1]
<-- [
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
]
無效的 RPC 批次呼叫:
--> [1,2,3]
<-- [
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null}
]
RPC 批次呼叫:
--> [
{"jsonrpc": "2.0", "method": "sum", "params": [1,2,4], "id": "1"},
{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]},
{"jsonrpc": "2.0", "method": "subtract", "params": [42,23], "id": "2"},
{"foo": "boo"},
{"jsonrpc": "2.0", "method": "foo.get", "params": {"name": "myself"}, "id": "5"},
{"jsonrpc": "2.0", "method": "get_data", "id": "9"}
]
<-- [
{"jsonrpc": "2.0", "result": 7, "id": "1"},
{"jsonrpc": "2.0", "result": 19, "id": "2"},
{"jsonrpc": "2.0", "error": {"code": -32600, "message": "Invalid Request"}, "id": null},
{"jsonrpc": "2.0", "error": {"code": -32601, "message": "Method not found"}, "id": "5"},
{"jsonrpc": "2.0", "result": ["hello", 5], "id": "9"}
]
所有都為通知的 RPC 批次呼叫:
--> [
{"jsonrpc": "2.0", "method": "notify_sum", "params": [1,2,4]},
{"jsonrpc": "2.0", "method": "notify_hello", "params": [7]}
]
擴充
[編輯]以 RPC 開頭的方法名預留作為系統擴充,且必須不能用於其他地方。每個系統擴充都應該有相關規範文件,所有系統擴充都應是可選的。