SOA (Service Oriented Architecture) wird durch Kombinieren und Interagieren von lose gekoppelten Diensten erstellt.Zur Demonstration erstellen wir zwei Anwendungen, Client und Server, und organisieren deren Interaktion mithilfe des Protokolls für Remoteprozeduraufrufe JSON-RPC 2.0.Kunde
Die Client-Anwendung ist eine Site zum Erstellen und Anzeigen bestimmter Inhalte. Der Client enthält keine eigene Datenbank, empfängt und fügt jedoch Daten aufgrund der Interaktion mit der Serveranwendung hinzu.Auf dem Client stellt die Interaktion eine Klasse bereitJsonRpcClientnamespace 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);
}
}
Wir brauchen eine Bibliothek GuzzleHttp, installieren Sie sie vor.Wir bilden eine ganz normale POSTAnfrage mit GuzzleHttp\Client. Die wichtigste Einschränkung hierbei ist das Anforderungsformat.Gemäß der Spezifikation sollte die JSON-RPC 2.0Anfrage wie folgt aussehen:{
"jsonrpc": "2.0",
"method": "getPageById",
"params": {
"page_uid": "f09f7c040131"
},
"id": "54645"
}
jsonrpc Protokollversion, muss "2.0" anzeigenmethod Methodennameparams Array mit Parameternid Anfrage ID
Antworten{
"jsonrpc": "2.0",
"result": {
"id": 2,
"title": "Index Page",
"content": "Content",
"description": "Description",
"page_uid": "f09f7c040131"
},
"id": "54645"
}
Wenn die Anfrage mit einem Fehler abgeschlossen wurde, erhalten wir{
"jsonrpc": "2.0",
"error": {
"code": -32700,
"message": "Parse error"
},
"id": "null"
}
jsonrpc Protokollversion, muss "2.0" anzeigenresultErforderliches Feld für ein erfolgreiches Abfrageergebnis. Sollte nicht existieren, wenn ein Fehler auftritterrorErforderliches Feld, wenn ein Fehler auftritt. Sollte bei erfolgreichem Ergebnis nicht existierenid Anforderungskennung vom Client festgelegt
Der Server bildet die Antwort, daher werden wir darauf zurückkommen.In der Steuerung ist es notwendig, eine Anfrage mit den notwendigen Parametern zu bilden und die Antwort zu verarbeiten.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']]);
}
}
Das feste JSON-RPC-Antwortformat macht es einfach, festzustellen, ob die Anforderung erfolgreich war, und Maßnahmen zu ergreifen, wenn die Antwort einen Fehler enthält.Server
Beginnen wir mit dem Einrichten des Routings. In der Datei routes/api.phphinzufügenRoute::post('/data', function (Request $request, JsonRpcServer $server, DataController $controller) {
return $server->handle($request, $controller);
});
Alle vom Server unter der Adresse empfangenen Anforderungen <server_base_uri>/datawerden von der Klasse verarbeitetJsonRpcServernamespace 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());
}
}
}
Die Klasse JsonRpcServerbindet die gewünschte Controller-Methode mit den übergebenen Parametern. Und es gibt die von der Klasse generierte Antwort JsonRpcResponsein dem Format zurück, das JSON-RPC 2.0der oben beschriebenen Spezifikation entspricht .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,
];
}
}
Es bleibt ein Controller hinzuzufügen.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;
}
}
Ich sehe keinen Grund, den Controller im Detail zu beschreiben, ganz Standardmethoden. Die Klasse DataCreateenthält die gesamte Logik zum Erstellen eines Objekts sowie zum Überprüfen der Gültigkeit von Feldern mit dem Auslösen der erforderlichen Ausnahme.Fazit
Ich habe versucht, die Logik der Anwendungen selbst nicht zu komplizieren, sondern mich auf ihre Interaktion zu konzentrieren.Die Vor- und Nachteile von JSON-RPC sind in einem Artikel gut beschrieben, auf den ich weiter unten verweisen werde. Dieser Ansatz ist beispielsweise bei der Implementierung eingebetteter Formulare relevant.Verweise