SOA(面向服务的体系结构)是通过组合和交互松散耦合的服务而构建的。为了演示,我们将创建两个应用程序Client和Server,并使用远程过程调用协议组织它们的交互JSON-RPC 2.0
。顾客
客户端应用程序是用于创建和显示某些内容的站点。客户端不包含其自己的数据库,但是由于与服务器应用程序的交互而接收并添加了数据。在客户端上,交互提供了一个类JsonRpcClient
namespace ClientApp\Services;
use GuzzleHttp\Client;
use GuzzleHttp\RequestOptions;
class JsonRpcClient
{
const JSON_RPC_VERSION = '2.0';
const METHOD_URI = 'data';
protected $client;
public function __construct()
{
$this->client = new Client([
'headers' => ['Content-Type' => 'application/json'],
'base_uri' => config('services.data.base_uri')
]);
}
public function send(string $method, array $params): array
{
$response = $this->client
->post(self::METHOD_URI, [
RequestOptions::JSON => [
'jsonrpc' => self::JSON_RPC_VERSION,
'id' => time(),
'method' => $method,
'params' => $params
]
])->getBody()->getContents();
return json_decode($response, true);
}
}
我们需要一个库GuzzleHttp
,预安装它。我们使用形成了一个完全标准的POST
请求GuzzleHttp\Client
。这里的主要警告是请求格式。根据规范,JSON-RPC 2.0
请求应如下所示:{
"jsonrpc": "2.0",
"method": "getPageById",
"params": {
"page_uid": "f09f7c040131"
},
"id": "54645"
}
jsonrpc
协议版本,必须表示“ 2.0”method
方法名称params
带参数的数组id
要求编号
回答{
"jsonrpc": "2.0",
"result": {
"id": 2,
"title": "Index Page",
"content": "Content",
"description": "Description",
"page_uid": "f09f7c040131"
},
"id": "54645"
}
如果请求完成但有错误,我们得到{
"jsonrpc": "2.0",
"error": {
"code": -32700,
"message": "Parse error"
},
"id": "null"
}
jsonrpc
协议版本,必须表示“ 2.0”result
成功查询结果的必填字段。发生错误时不应该存在error
发生错误时的必填字段。成功结果不应该存在id
客户设置的请求标识符
服务器构成了答案,因此我们将回到它。在控制器中,有必要形成具有必要参数的请求并处理响应。namespace ClientApp\Http\Controllers;
use App\Services\JsonRpcClient;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Redirect;
class SiteController extends Controller
{
protected $client;
public function __construct(JsonRpcClient $client)
{
$this->client = $client;
}
public function show(Request $request)
{
$data = $this->client->send('getPageById', ['page_uid' => $request->get('page_uid')]);
if (empty($data['result'])) {
abort(404);
}
return view('page', ['data' => $data['result']]);
}
public function create()
{
return view('create-form');
}
public function store(Request $request)
{
$data = $this->client->send('create', $request->all());
if (isset($data['error'])) {
return Redirect::back()->withErrors($data['error']);
}
return view('page', ['data' => $data['result']]);
}
}
JSON-RPC固定响应格式可以轻松查看请求是否成功,如果响应包含错误,则可以采取任何措施。服务器
让我们从设置路由开始。在文件中routes/api.php
添加Route::post('/data', function (Request $request, JsonRpcServer $server, DataController $controller) {
return $server->handle($request, $controller);
});
服务器在该地址接收到的所有请求<server_base_uri>/data
将由该类处理JsonRpcServer
namespace ServerApp\Services;
class JsonRpcServer
{
public function handle(Request $request, Controller $controller)
{
try {
$content = json_decode($request->getContent(), true);
if (empty($content)) {
throw new JsonRpcException('Parse error', JsonRpcException::PARSE_ERROR);
}
$result = $controller->{$content['method']}(...[$content['params']]);
return JsonRpcResponse::success($result, $content['id']);
} catch (\Exception $e) {
return JsonRpcResponse::error($e->getMessage());
}
}
}
该类JsonRpcServer
将所需的控制器方法与传递的参数绑定在一起。并JsonRpcResponse
以上述规范的格式返回由类生成的响应JSON-RPC 2.0
。use ServerApp\Http\Response;
class JsonRpcResponse
{
const JSON_RPC_VERSION = '2.0';
public static function success($result, string $id = null)
{
return [
'jsonrpc' => self::JSON_RPC_VERSION,
'result' => $result,
'id' => $id,
];
}
public static function error($error)
{
return [
'jsonrpc' => self::JSON_RPC_VERSION,
'error' => $error,
'id' => null,
];
}
}
仍然需要添加控制器。namespace ServerApp\Http\Controllers;
class DataController extends Controller
{
public function getPageById(array $params)
{
$data = Data::where('page_uid', $params['page_uid'])->first();
return $data;
}
public function create(array $params)
{
$data = DataCreate::create($params);
return $data;
}
}
我认为没有理由详细描述控制器,这是非常标准的方法。该类DataCreate
包含创建对象的所有逻辑,并通过引发必要的异常来检查字段的有效性。结论
我试图不使应用程序本身的逻辑复杂化,而是将重点放在它们的交互上。JSON-RPC的优缺点在一篇文章中写得很好,我将在下面提供指向该文章的链接。例如,在实现嵌入式表单时,此方法很重要。参考文献