Laravel的路由設(shè)置非常簡(jiǎn)單询一,但是在大型項(xiàng)目中需要配置很多路由信息滤钱,顯得比較臃腫,可以對(duì)路由進(jìn)行如下簡(jiǎn)化:
首先創(chuàng)建一個(gè)中間件 HttpDiscernMiddleware:
<?php
namespace App\Http\Middleware;
use Closure;
use Log;
use App;
class HttpDiscernMiddleware
{
protected $controller;
protected $method;
protected $api_version;
/**
* Request Method&Api Version Discern Middleware
* @param $request
* @param Closure $next
* @return mixed
* @throws \Exception
*/
public function handle($request, Closure $next)
{
$real_method = $request->getRealMethod();
$scheme_host = $request->getSchemeAndHttpHost();
$request_uri = $request->getRequestUri();
$client_ip = $request->getClientIp();
$content_type = $request->getContentType();
$base_url = $request->getBaseUrl();
$data = [
"real_method"=>$real_method,
"scheme_host"=>$scheme_host,
"request_uri"=>$request_uri,
"client_ip"=>$client_ip,
"content_type"=>$content_type,
"base_url"=>$base_url,
];
Log::info("Http Request : ".json_encode($data));
if (strrpos($request_uri,'?')) {
$temp = explode('?', $request_uri);
$temp = explode('/', current($temp));
}else{
$temp = explode('/', $request_uri);
}
$this->controller = $temp[1];
$this->method = $temp[2];
try {
if (strtolower($this->controller)=="api") {
$this->api_version = $temp[2];
$this->controller = $temp[3];
$this->method = $temp[4];
}
$tag = ['@method','@api'];
$request_method = $this->getProperty(
'App\Http\Controllers\\'.ucwords($this->controller).'Controller',
$this->method,
$tag
);
Log::info("request_method: ",$request_method);
if ($request_method['@method'] != strtolower($real_method)) {
throw new \Exception('方法不支持');
}
if (!empty($request_method['@api'])) {
if (empty($this->api_version)) {
throw new \Exception("@api 版本為空");
}
$api = (float) explode(':', $request_method['@api'])[1];
$req_api = (float) explode('v',$this->api_version)[1];
if ($api != $req_api) {
throw new \Exception("@api 版本不正確");
}
}
} catch (\Exception $e) {
throw $e;
}
return $next($request);
}
/**
* Get Class Property Function
* @param $class
* @param $method
* @param $tags
* @return array|null
* @throws \Exception
*/
public function getProperty($class, $method, $tags)
{
try {
$req_property = null;
if (empty($tags)) {
throw new \Exception('Tag 不能空');
}
$controller = new \ReflectionClass($class);
$method = $controller->getMethod($method);
$doc = $method->getDocComment();
$matches = array();
$req_property = array();
foreach ($tags as $item) {
preg_match("/".$item."(.*)(\\r\\n|\\r|\\n)/U", $doc, $matches);
if (isset($matches[1])) {
$req_property[$item] =trim($matches[1]) ;
}
}
if (!isset($req_property['@method'])) {
throw new \Exception('請(qǐng)?jiān)O(shè)置@method 屬性[必填]');
}
return $req_property;
} catch (\Exception $e) {
throw $e;
}
}
}
HttpDiscernMiddleware的任務(wù)是完成用戶請(qǐng)求和Controller中的方法進(jìn)行匹配拔恰,通過(guò)反射獲取Controller中Function注釋信息(@method,@api)玖绿,這樣可以不需要在routes文件夾下配置很多路由信息了;
在Kernel.php,$routeMiddleware中配置如下:
'discern'=> \App\Http\Middleware\HttpDiscernMiddleware::class,
在RouteServiceProvider 中加入:
public function boot()
{
//
parent::boot();
Route::bind('controller', function ($controller) {
try {
return app($this->namespace.'\\'.ucwords($controller).'Controller');
} catch (\Exception $e) {
throw new \Exception('Controller 解析失敗');
}
});
}
綁定$controller變量為解析后的Controller對(duì)象 ;
然后在routes/web.php中 加入:
Route::group([
'middleware'=>[
'discern'
]
],function () {
Route::match(['get','post','put','delete','patch'],'/{controller}/{method}',function ($controller,$method){
try {
$result = $controller->$method();
if(is_scalar($result)){
return response()->json($result);
}
return $result;
} catch (\Exception $e) {
throw new Exception($e->getMessage());
}
});
});
在routes/api.php中加入:
Route::group([
'middleware'=>[
'discern'
]
],function () {
Route::match(['get','post','put','delete','patch'],'/{version}/{controller}/{method}',function ($version,$controller,$method){
try {
$result = $controller->$method();
if(is_scalar($result)){
return response()->json($result);
}
return $result;
} catch (\Exception $e) {
throw new Exception($e->getMessage());
}
});
});
這樣就配置好web.php 和 api.php了年堆。
這些配置好后就只需要在控制器中配置請(qǐng)求method或者api版本信息 就可以了吞杭,不需要寫繁瑣的路由信息,當(dāng)然可以根據(jù)自己的需要修改变丧。
Demo1: [ 請(qǐng)求uri : http://domain/demo/testGet?user=ethan]
class DemoController extends Controller
{
/**
* Controller-Route Demo
* @method get
* @return array
*/
public function testGet()
{
$user = $this->getParam("user");
return view('home')->with($user);
}
}
@method 定義了請(qǐng)求的方法必須為get
Demo2: [ 請(qǐng)求uri : http://domain/api/v1/demo/testGet?user=ethan]
class DemoController extends Controller
{
/**
* Controller-Route Demo
* @method get
* @api version:1.0
* @return array
*/
public function testGet()
{
$user = $this->getParam("user");
return view('home')->with($user);
}
}
@method 定義了請(qǐng)求的方法必須為get芽狗,@api 定義了版本為v1(v是version的簡(jiǎn)寫)
其中 @method 支持 [get,post痒蓬,put童擎,delete]
通過(guò)Demo1和Demo2可以通過(guò)注釋來(lái)控制route路由的請(qǐng)求規(guī)則了,達(dá)到了簡(jiǎn)化路由的目的攻晒,并且使用很方便顾复。