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