JSON-RPC 是輕量級遠端呼叫協定,以 JSON 為訊息格式,支援 HTTP 等傳輸層。本文提供一組極簡的 PHP Server/Client 實作,展示核心流程:請求解析、方法分派、回應封裝、錯誤處理。
<?php
class JsonRPCServer {
public static function handle(object $service): bool {
// 僅接受 POST + application/json
if ($_SERVER['REQUEST_METHOD'] !== 'POST' ||
empty($_SERVER['CONTENT_TYPE']) ||
stripos($_SERVER['CONTENT_TYPE'], 'application/json') === false) {
return false;
}
$input = file_get_contents('php://input');
$request = json_decode($input, true);
if (!isset($request['method'], $request['params'], $request['id'])) {
self::respond(null, -32600, 'Invalid Request');
return true;
}
try {
if (!method_exists($service, $request['method'])) {
throw new Exception('Method not found', -32601);
}
$result = call_user_func_array([$service, $request['method']], $request['params']);
self::respond($request['id'], null, $result);
} catch (Throwable $e) {
self::respond($request['id'], $e->getCode() ?: -32603, $e->getMessage());
}
return true;
}
private static function respond($id, $error, $result = null): void {
header('Content-Type: application/json');
$payload = ['jsonrpc' => '2.0', 'id' => $id];
if ($error !== null) {
$payload['error'] = ['code' => $error, 'message' => $result];
} else {
$payload['result'] = $result;
}
echo json_encode($payload);
}
}
?>
<?php
class JsonRPCClient {
private string $url;
private int $id = 1;
private bool $debug = false;
public function __construct(string $url, bool $debug = false) {
$this->url = $url;
$this->debug = $debug;
}
public function __call(string $method, array $params) {
$request = [
'jsonrpc' => '2.0',
'method' => $method,
'params' => array_values($params[0] ?? []), // 支援 call($method, [params...])
'id' => $this->id++,
];
$payload = json_encode($request);
$ctx = stream_context_create([
'http' => [
'method' => 'POST',
'header' => 'Content-Type: application/json',
'content' => $payload,
'timeout' => 10,
]
]);
$response = @file_get_contents($this->url, false, $ctx);
if ($response === false) throw new Exception("Connection failed: {$this->url}");
$data = json_decode($response, true);
if ($this->debug) var_dump($data);
if (isset($data['error'])) throw new Exception($data['error']['message'], $data['error']['code']);
return $data['result'] ?? null;
}
}
?>
// member.php - 服務類
class Member {
public function getName(): string { return 'Hello JSON-RPC'; }
public function add(int $a, int $b): int { return $a + $b; }
}
// server.php
require 'jsonRPCServer.php';
require 'member.php';
JsonRPCServer::handle(new Member()) or exit('No request');
// client.php
require 'jsonRPCClient.php';
$client = new JsonRPCClient('https://localhost/rpc/server.php');
echo $client->getName(); // Hello JSON-RPC
echo $client->add(3, 5); // 8