如同第三章所介紹的,Anser 分為三大部分。在這個單元中,將會聚焦在「Service」的設計理念與各類別的使用方式。
上圖顯示的是一個簡單的 Service 子系統元件或類別的相依關係圖。
在這篇文章中我們會使用到 Production Service 與 Main App,請參考第四章節所提到的內容建立你的本地開發環境。
你可以透過 Command Line 介面 cd
至專案根目錄,使用 docker compose up -d
分別打開你的本地範例微服務與開發環境。
首先,先將 Command Line 定位至 Main Service 專案根目錄,並透過 docker compose exec app bash
進入到專案的 docker 容器之中。
接著,使用以下指令安裝 anser-action
程式庫。
composer require sdpmlab/anser-action
順利的話,你會看到以下畫面響應,等待它們安裝完畢即可。
當安裝完畢後,你的 Main Service 目錄可能會長得像是這個樣子:
我們建立一個名為 action_test.php
的 PHP 檔案,並貼上以下內容:
<?php
require_once './vendor/autoload.php';
use \SDPMlab\Anser\Service\Action;
use \Psr\Http\Message\ResponseInterface;
$action = (new Action(
serviceName: "https://httpbin.org",
method: "GET",
path: "/get"
))->doneHandler(static function(
ResponseInterface $response,
Action $runtimeAction
){
$body = $response->getBody()->getContents();
$data = json_decode($body, true);
$runtimeAction->setMeaningData($data);
});
$data = $action->do()->getMeaningData();
header("Content-Type: application/json");
echo json_encode($data);
這是一個 httpbin.org 的測試連線。首先我們透過 new Action()
定義一個 Action 物件,在建構 Action 物件時你需要傳入三個參數,分別是:
string $serviceName
:服務名稱或端點網址(Endpoint URL)string $method
:本次連線的 HTTP 動詞string $path
:資源的路徑接著,我們透過設定 doneHandler
去定義當 http 連線執行成功時的處理行為,這裡是透過 json_decode
的方式解析 HTTP Response Body 。
最後關注第 19 行。執行 Action 的 do()
方法即可發出 HTTP 請求,再以 getMeaningData()
取得在 doneHandler
中解析完畢的資料。
你可以透過 Command Line 介面在容器內執行:
php action_test.php
順利的話你會看見下述響應畫面:
或者是透過 postman 以 HTTP 連線執行你的測試用 PHP,像這樣:
當看到上述畫面,代表你成功地在你的環境中透過 Action 物件進行了一個 HTTP Get 請求,並成功處理響應後的 Response Body ,經過解析後再轉由 PHP 進行結果輸出。
Anser 提供能夠被全域呼叫的物件 ServiceList
,這個物件採用單例設計模式(Singleton Pattern)實作,它包含了服務的連線清單以及唯一且共用的 HTTP-Client 物件。
開發人 員能夠依據應用的框架或軟體架構的不同,在任何合適的執行期間(Runtime)透過 ServiceList
提供的靜態方法定義服務的名稱、IP 位置、連接埠以及 SSL 相關設定:
setLocalServices()
:傳入 key/value 陣列,在一次的呼叫中設定所有的參與的微服務。addLocalService()
:僅設定一組微服務資訊,並將此資訊加入到全域的 localServiceList
。無論你採用哪種方式宣告你的服務,它們都需要傳入下列參數進行設定:
string $name
:服務名稱,在 Action
物件中能夠以這個名稱代表現在所設定的這個服務string $address
:服務連線位置,可以是 IP、Domain 或是本系列文章所使用範例 Docker Compose Service Nameint $port
:填入目標服務的 HTTP 服務 Portbool $isHttps
:是否採用加密連線讓我們來試試看吧!
在你的開發環境中建立一個 init.php
並鍵入下列內容:
<?php
require_once './vendor/autoload.php';
use SDPMlab\Anser\Service\ServiceList;
ServiceList::addLocalService(
name: "ProductionService",
address: "production-service",
port: 8080,
isHttps: false
);
//等同於
// ServiceList::setLocalServices([
// [
// "name" => "ProductionService",
// "address" => "production-service",
// "port" => 8080,
// "isHttps" => false
// ],
// ]);
在上述檔案中,在第 2 行處理了 Composer 自動載入,接著從第 6 行開始設定第一個服務連線資訊。
無論是第 8 行的 setLocalServices()
或是第 16 行的 setLocalServices()
,他們的效果都是一樣的,你可以依照你的開發喜好選擇你想要的方式宣告。
而當你做完了服務宣告後, Anser 內的所有類別將會依照 ServiceList 中的成員變數 localServiceList
來取得微服務的連線資訊。
在你的開發環境中再建立一個新檔案 get_product.php
,貼上以下內容:
<?php
require_once './init.php';
use SDPMlab\Anser\Service\Action;
use Psr\Http\Message\ResponseInterface;
$action = (new Action(
serviceName: "ProductionService",
method: "GET",
path: "/api/v1/products"
))->doneHandler(static function(
ResponseInterface $response,
Action $runtimeAction
){
$body = $response->getBody()->getContents();
$data = json_decode($body, true);
$runtimeAction->setMeaningData($data);
});
$data = $action->do()->getMeaningData();
header("Content-Type: application/json");
echo json_encode($data) . PHP_EOL;
你依舊可以選擇使用 Command 介面或 Postman 執行你的程式碼,順利的話你會看見來自於 Production Service 的響應結果,我們將可以獲得產品清單:
由於我們在 init.php
中已經進行了 require_once './vendor/autoload.php';
,所以在 get_product.php
中我們只需要 require_once './init.php'
。同時,init.php
也替我們宣告了所需的 Service。
你可以關注第 8 行,我們只需要傳入正確的 Service Name ,即可以透過在 ServiceList
中宣告的連線資訊驅動 Action 往目標 Service 發出請求。
透過本章的介紹,讀者應能大抵理解 Anser 的 Service 子系統如何運作,以及其所包含的核心元件如 Action、Service List 的基本使用方法,以及其他元件的粗略介紹。
透過 Action 物件,我們希望 HTTP 連線變得簡單,還可以透過各種 Handler 與 Filter 定義出極具彈性的連線行為。加上 Service List 的協助,開發者能統一管理所有的微服務連線資訊,大大提高開發效率及維護性。