注意
webman版本>=1.2時請使用 webman/action-hook插件 實現(xiàn)beforeAction()
afterAction()
。
否則請參考以下教程手動配置注意
webman版本>=1.4.6 時,webman默認關(guān)閉了控制器復(fù)用,可以直接使用控制器__construct()
為每個請求初始化工作
在傳統(tǒng)框架中,每個請求都會實例化一次控制器,所以很多開發(fā)者__construct()
方法中做一些請求前的準(zhǔn)備工作。
而webman由于控制器常駐內(nèi)存,無法在__construct()
里做這些工作,不過webman提供了更好的解決方案beforeAction()
afterAction()
,它不僅讓開發(fā)者可以介入到請求前的流程中,而且還可以介入到請求后的處理流程中。
為了介入請求流程,我們需要使用中間件
1、創(chuàng)建文件 app/middleware/ActionHook.php
(middleware目錄不存在請自行創(chuàng)建)
<?php
namespace app\middleware;
use support\Container;
use Webman\MiddlewareInterface;
use Webman\Http\Response;
use Webman\Http\Request;
use Webman\Route;
class ActionHook implements MiddlewareInterface
{
public function process(Request $request, callable $next) : Response
{
if ($request->controller) {
// 禁止直接訪問beforeAction afterAction
if ($request->action === 'beforeAction' || $request->action === 'afterAction') {
$callback = Route::getFallback() ?? function () {
return new Response(404, [], \file_get_contents(public_path() . '/404.html'));
};
$reponse = $callback($request);
return $reponse instanceof Response ? $reponse : \response($reponse);
}
$controller = Container::get($request->controller);
if (method_exists($controller, 'beforeAction')) {
$before_response = call_user_func([$controller, 'beforeAction'], $request);
if ($before_response instanceof Response) {
return $before_response;
}
}
$response = $next($request);
if (method_exists($controller, 'afterAction')) {
$after_response = call_user_func([$controller, 'afterAction'], $request, $response);
if ($after_response instanceof Response) {
return $after_response;
}
}
return $response;
}
return $next($request);
}
}
2、在 config/middleware.php 中添加如下配置
return [
'' => [
// .... 這里省略了其它配置 ....
app\middleware\ActionHook::class,
]
];
3、這樣如果 controller包含了 beforeAction
或者 afterAction
方法會在請求發(fā)生時自動被調(diào)用。
例如:
<?php
namespace app\controller;
use support\Request;
class Index
{
/**
* 該方法會在請求前調(diào)用
*/
public function beforeAction(Request $request)
{
echo 'beforeAction';
// 若果想終止執(zhí)行Action就直接返回Response對象,不想終止則無需return
// return response('終止執(zhí)行Action');
}
/**
* 該方法會在請求后調(diào)用
*/
public function afterAction(Request $request, $response)
{
echo 'afterAction';
// 如果想串改請求結(jié)果,可以直接返回一個新的Response對象
// return response('afterAction');
}
public function index(Request $request)
{
return response('index');
}
}
Request
對象給beforeAction
,開發(fā)者可以從中獲得用戶輸入beforeAction
里返回一個Response
對象,比如return redirect('/user/login');
Request
對象以及Response
對象給afterAction
,開發(fā)者可以從中獲得用戶輸入以及控制器執(zhí)行后返回的響應(yīng)結(jié)果$response->rawBody()
獲得響應(yīng)內(nèi)容$response->getHeader()
獲得響應(yīng)的header頭$response->getStatusCode()
獲得響應(yīng)的http狀態(tài)碼$response->withBody()
$response->header()
$response->withStatus()
串改響應(yīng),也可以創(chuàng)建并返回一個新的Response
對象替代原響應(yīng)觸發(fā)路由404異常
路由配置文件route.php
增加以下選項
use Tinywan\ExceptionHandler\Exception\RouteNotFoundException;
...
Route::fallback(function () {
throw new RouteNotFoundException();
});
假設(shè)訪問以下接口地址(不存在的路由)
http://127.0.0.1:8888/test/route-not-exist
該地址路由不存在,即沒在
route.php
配置文件中
接口響應(yīng)輸出
HTTP/1.1 404 Not Found
Content-Type: application/json;charset=UTF-8
{
"code": 0,
"msg": "路由地址不存在",
"data": {
"request_url": "GET //127.0.0.1:8888/test/route-not-exist",
"timestamp": "2022-03-19 14:34:36",
"client_ip": "172.18.0.1",
"request_param": []
}
}
異常處理
// 不需要記錄錯誤日志
'dont_report' => [
Tinywan\ExceptionHandler\Exception\NotFoundHttpException::class,
]
這樣就不會記錄很多無用的異常日志
use Tinywan\ExceptionHandler\Exception\RouteNotFoundException;
..
// 禁止直接訪問beforeAction afterAction
if ($request->action === 'beforeAction' || $request->action === 'afterAction') {
throw new RouteNotFoundException();
}
在BeforeAction中無法改變Controller中的屬性值。
例如在ArticleController定義一個public 屬性 $pageInfo, 在beforeAction中賦值$this->pageInfo, 在Action中發(fā)現(xiàn)并未寫入。