fguillot/json-rpc

简单易用的JSON-RPC客户端/服务器库

v1.3.0 2024-06-08 19:21 UTC

This package is auto-updated.

Last update: 2024-09-10 08:18:16 UTC


README

CI workflow

这是一个简单易用的JSON-RPC客户端/服务器。

特性

  • 仅支持JSON-RPC 2.0
  • 服务器支持批量请求和通知
  • 基于IP的客户限制和身份验证
  • 自定义中间件
  • 完全单元测试
  • 许可: MIT

贡献者

Frédéric Guillot以及许多其他人

Contributors

使用Composer安装

composer require fguillot/json-rpc

示例

Symfony

服务器

回调绑定

<?php

use JsonRPC\Server;

$server = new Server();
$server->getProcedureHandler()
    ->withCallback('addition', function ($a, $b) {
        return $a + $b;
    })
    ->withCallback('random', function ($start, $end) {
        return mt_rand($start, $end);
    })
;

echo $server->execute();

从数组中绑定回调

<?php

use JsonRPC\Server;

$callbacks = [
    'getA' => function() { return 'A'; },
    'getB' => function() { return 'B'; },
    'getC' => function() { return 'C'; }
];

$server = new Server();
$server->getProcedureHandler()->withCallbackArray($callbacks);

echo $server->execute();

类/方法绑定

<?php

use JsonRPC\Server;

class Api
{
    public function doSomething($arg1, $arg2 = 3)
    {
        return $arg1 + $arg2;
    }
}

$server = new Server();
$procedureHandler = $server->getProcedureHandler();

// Bind the method Api::doSomething() to the procedure myProcedure
$procedureHandler->withClassAndMethod('myProcedure', 'Api', 'doSomething');

// Use a class instance instead of the class name
$procedureHandler->withClassAndMethod('mySecondProcedure', new Api, 'doSomething');

// The procedure and the method are the same
$procedureHandler->withClassAndMethod('doSomething', 'Api');

// Attach the class, the client will be able to call directly Api::doSomething()
$procedureHandler->withObject(new Api());

echo $server->execute();

从数组中绑定类/方法

<?php

use JsonRPC\Server;

class MathApi
{
    public function addition($arg1, $arg2)
    {
        return $arg1 + $arg2;
    }

    public function subtraction($arg1, $arg2)
    {
        return $arg1 - $arg2;
    }

    public function multiplication($arg1, $arg2)
    {
        return $arg1 * $arg2;
    }

    public function division($arg1, $arg2)
    {
        return $arg1 / $arg2;
    }
}

$callbacks = [
    'addition'       => [ 'MathApi', addition ],
    'subtraction'    => [ 'MathApi', subtraction ],
    'multiplication' => [ 'MathApi', multiplication ,
    'division'       => [ 'MathApi', division ],
];

$server = new Server();
$server->getProcedureHandler()->withClassAndMethodArray($callbacks);

echo $server->execute();

服务器中间件

中间件可以用于对客户端进行身份验证和授权。它们在每个过程执行之前执行。

<?php

use JsonRPC\Server;
use JsonRPC\MiddlewareInterface;
use JsonRPC\Exception\AuthenticationFailureException;

class Api
{
    public function doSomething($arg1, $arg2 = 3)
    {
        return $arg1 + $arg2;
    }
}

class MyMiddleware implements MiddlewareInterface
{
    public function execute($username, $password, $procedureName)
    {
        if ($username !== 'foobar') {
            throw new AuthenticationFailureException('Wrong credentials!');
        }
    }
}

$server = new Server();
$server->getMiddlewareHandler()->withMiddleware(new MyMiddleware());
$server->getProcedureHandler()->withObject(new Api());
echo $server->execute();

当API凭证错误时,您可以抛出AuthenticationFailureException,当用户不允许访问过程时,您可以抛出AccessDeniedException

客户端

使用位置参数的示例

<?php

use JsonRPC\Client;

$client = new Client('http://localhost/server.php');
$result = $client->execute('addition', [3, 5]);

使用命名参数的示例

<?php

use JsonRPC\Client;

$client = new Client('http://localhost/server.php');
$result = $client->execute('random', ['end' => 10, 'start' => 1]);

参数按正确顺序调用。

使用魔术方法__call()的示例

<?php

use JsonRPC\Client;

$client = new Client('http://localhost/server.php');
$result = $client->random(50, 100);

上面的示例使用位置参数进行请求,而本例使用命名参数。

$result = $client->random(['end' => 10, 'start' => 1]);

客户端批量请求

在单个HTTP请求中调用多个过程

<?php

use JsonRPC\Client;

$client = new Client('http://localhost/server.php');

$results = $client->batch()
                  ->foo(['arg1' => 'bar'])
                  ->random(1, 100)
                  ->add(4, 3)
                  ->execute('add', [2, 5])
                  ->send();

print_r($results);

所有结果都存储在调用相同的同一位置。

客户端异常

客户端异常通常在服务器返回错误时抛出。您可以通过使用$returnException参数来更改此行为,这将导致返回异常。这在执行批量请求时非常有用。

  • BadFunctionCallException:服务器上找不到过程
  • InvalidArgumentException:过程参数错误
  • JsonRPC\Exception\AccessDeniedException:拒绝访问
  • JsonRPC\Exception\ConnectionFailureException:连接失败
  • JsonRPC\Exception\ServerErrorException:内部服务器错误

启用客户端调试

您可以通过启用调试模式来查看JSON请求和响应。

<?php

use JsonRPC\Client;

$client = new Client('http://localhost/server.php');
$client->getHttpClient()->withDebug();

调试输出发送到PHP系统日志。您可以在您的php.ini中配置日志目标。

输出示例

==> Request:
{
    "jsonrpc": "2.0",
    "method": "removeCategory",
    "id": 486782327,
    "params": [
        1
    ]
}
==> Response:
{
    "jsonrpc": "2.0",
    "id": 486782327,
    "result": true
}

基于IP的客户限制

服务器可以仅允许某些IP地址。

<?php

use JsonRPC\Server;

$server = new Server;

// IP client restrictions
$server->allowHosts(['192.168.0.1', '127.0.0.1']);

...

// Return the response to the client
echo $server->execute();

如果客户端被阻止,您将收到403禁止的HTTP响应。

HTTP基本身份验证

如果您使用HTTPS,您可以使用用户名/密码允许客户端。

<?php

use JsonRPC\Server;

$server = new Server;

// List of users to allow
$server->authentication(['user1' => 'password1', 'user2' => 'password2']);

...

// Return the response to the client
echo $server->execute();

在客户端,设置凭证如下

<?php

use JsonRPC\Client;

$client = new Client('http://localhost/server.php');
$client->getHttpClient()
    ->withUsername('Foo')
    ->withPassword('Bar');

如果身份验证失败,客户端将抛出RuntimeException。

使用替代身份验证头

use JsonRPC\Server;

$server = new Server();
$server->setAuthenticationHeader('X-Authentication');
$server->authentication(['myusername' => 'mypassword']);

上面的示例将使用HTTP头X-Authentication而不是标准的Authorization: Basic [BASE64_CREDENTIALS]。用户名/密码值需要使用base64编码:base64_encode('username:password')

本地异常

默认情况下,服务器将所有异常转给客户端。如果您只想转交其中的一些,请使用方法Server::withLocalException($exception)

<?php

use JsonRPC\Server;
class MyException1 extends Exception {};
class MyException2 extends Exception {};

$server = new Server();

// Exceptions that should NOT be relayed to the client, if they occurs
$server
    ->withLocalException('MyException1')
    ->withLocalException('MyException2')
;

...

echo $server->execute();

客户端请求前的回调

您可以使用回调在请求服务器之前更改HTTP头或URL。

示例

<?php

$client = new Client();
$client->getHttpClient()->withBeforeRequestCallback(function(HttpClient $client, $payload) {
    $client->withHeaders(['Content-Length: '.strlen($payload)]);
});

$client->myProcedure(123);