تم بناء بنية SOA (هندسة المنحى الخدمي) من خلال الجمع بين الخدمات المقترنة بشكل فضفاض والتفاعل معها.للتوضيح ، سننشئ تطبيقين ، العميل والخادم ، وننظم تفاعلهما باستخدام بروتوكول استدعاء الإجراء البعيد 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 جيدًا في المقالة ، وهو الرابط الذي سأتركه أدناه. يعتبر هذا النهج مناسبًا ، على سبيل المثال ، عند تنفيذ النماذج المضمنة.المراجع