routemidlleware 不支持 terminate 這是基於什麼考慮的。不管 laravel 還是 lumen 只有 global middleware 纔會去 call terminate 而 routemiddleware 卻不會
中間件文件都放在app/http/Middleware文件夾中,可以根據ExampleMiddleware.php進行創建
前置中間件
namespace App\Http\Middleware;
use Closure;
define('START', microtime(true));
class BeforeMiddleware
{
//第三個參數爲額外傳參
public function handle($request, Closure $next)
{
//前置中間件,在執行路由定義指定的操作前做你想做的事情
return $next($request);
}
}
後置中間件
<?php
namespace App\Http\Middleware;
use Closure;
class AfterMiddleware
{
//第三個參數爲額外傳參
public function handle($request, Closure $next)
{
$response = $next($request);
//後置中間件,在執行完路由定義指定的操作後(也就是響應前)做你想做的事情
echo 1;
return $response;
}
}
全局中間件
每個 HTTP 請求都經過一箇中間件,只要將中間件的類加入到 bootstrap/app.php 的 $app->middleware() 調用參數數組中。
$app->middleware([
App\Http\Middleware\Authenticate::class,
]);
Terminable中間件
有些時候中間件需要在 HTTP 響應被髮送到瀏覽器之後才運行,例如,「session」中間件存儲的 session 數據是在響應被髮送到瀏覽器之後才進行寫入的。想要做到這一點,你需要定義中間件爲「terminable」。
<?php
namespace Illuminate\Session\Middleware;
use Closure;
use Illuminate\Support\Facades\Log;
class StartSession
{
public function handle($request, Closure $next)
{
// 開始
Log::info($_SERVER['REQUEST_URI'].'開始'.START.'微秒');
return $next($request);
}
public function terminate($request, $response)
{
//結束
$end = microtime(true);
Log::info($_SERVER['REQUEST_URI'].'結束'.$end.'微秒');
$diff = ($end-START) * 1000;
if ($diff >= 1500) {
Log::info("接口{".$_SERVER['REQUEST_URI']."}從請求開始到結束相差{$diff}毫秒");
}
}
}
terminate
方法必須接收請求及響應。一旦定義了 terminable 中間件,你便需要將它增加到 bootstrap/app.php
文件的全局中間件清單列表中。
當在你的中間件調用 terminate
方法時,Lumen 會從 服務容器 解析一個全新的中間件實例。
如果你希望在 handle
及 terminate
方法被調用時使用一致的中間件實例,只需在容器中使用容器的 singleton
方法註冊中間件。
$app->singleton(
App\Http\Middleware\terminable::class
);
如果上面的代碼個別接口執行不到terminate的話(這裏是坑,至今未找到原因),你可以嘗試以下方法
在底層控制器中的的構造方法__construct中註冊函數register_shutdown_function
註冊一個 callback
,它會在腳本執行完成或者 exit() 後被調用。
可以多次調用 register_shutdown_function() ,這些被註冊的回調會按照他們註冊時的順序被依次調用。 如果你在註冊的方法內部調用 exit(), 那麼所有處理會被中止,並且其他註冊的中止回調也不會再被調用
public function __construct()
{
register_shutdown_function(array($this, 'test'));
}
public function test()
{
//成功完成後置中間件裏的內容
// TODO 切記 請勿die/exit
}