diff --git a/src/Api/ApiServiceProvider.php b/src/Api/ApiServiceProvider.php index eeaa666e775ebc1e38178f1b3e78123f63de1c05..e3c2c8ab006e8f581d942587a86ec71839c2d5c0 100644 --- a/src/Api/ApiServiceProvider.php +++ b/src/Api/ApiServiceProvider.php @@ -130,33 +130,14 @@ class ApiServiceProvider extends ServiceProvider require $this->app->basePath('routes/api.php'); }); } else if ($this->matchPrefix($reqUri, $pluginApiPrefix)) { - $this->setPluginRoutes($route, $pluginName); +// $this->setPluginRoutes($route,$plugins, $pluginName); } else { $route->group($userApiPrefix, function (RouteCollection $route) { require $this->app->basePath('routes/api.php'); }); } - } - - - private function setPluginRoutes(RouteCollection $route, $pluginName) - { - $plugins = \Discuz\Common\Utils::getPluginList(); - $plugin = array_filter($plugins, function ($item) use ($pluginName) { - return strtolower($item['name_en']) == strtolower($pluginName); - }); - $plugin = current($plugin); - if (empty($plugin)) exit('plugin ' . $pluginName . ' not exist.'); - $prefix = '/plugin/' . $plugin['name_en'] . '/api/'; - $route->group($prefix, function (RouteCollection $route) use ($plugin) { - $pluginFiles = $plugin['plugin_' . $plugin['app_id']]; - Utils::setPluginAppId($plugin['app_id']); - if (isset($pluginFiles['routes'])) { - foreach ($pluginFiles['routes'] as $routeFile) { - require_once $routeFile; - } - } - }); + \Discuz\Common\Utils::includePluginRoutes($route); + \Discuz\Common\Utils::setRouteMap($route->getRouteData()); } private function matchPrefix($uri, $prefix) diff --git a/src/Common/Utils.php b/src/Common/Utils.php index f5fca08fece29d19146410c1669b96cd2b776d7d..4d2c461b5f10a610fa90152488629f6a3056f6f6 100644 --- a/src/Common/Utils.php +++ b/src/Common/Utils.php @@ -7,6 +7,7 @@ use App\Common\DzqConst; use App\Common\ResponseCode; use Discuz\Base\DzqCache; use Discuz\Base\DzqLog; +use Discuz\Http\RouteCollection; use Illuminate\Http\Request; use Illuminate\Support\Str; use Discuz\Http\DiscuzResponseFactory; @@ -249,6 +250,27 @@ class Utils return $plugins; } + /** + * @desc 一次性加载所有插件的路由文件 + * @param RouteCollection $route + * @return RouteCollection + */ + public static function includePluginRoutes(RouteCollection &$route){ + $plugins = self::getPluginList(); + foreach ($plugins as $plugin) { + $prefix = '/plugin/' . $plugin['name_en'] . '/api/'; + $route->group($prefix, function (RouteCollection $route) use ($plugin) { + $pluginFiles = $plugin['plugin_' . $plugin['app_id']]; + \App\Common\Utils::setPluginAppId($plugin['app_id']); + if (isset($pluginFiles['routes'])) { + foreach ($pluginFiles['routes'] as $routeFile) { + require_once $routeFile; + } + } + }); + } + return $route; + } public static function runConsoleCmd($cmd, $params) { $reader = function & ($object, $property) { @@ -406,4 +428,28 @@ class Utils mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff) ); } + + public static function setAppKey($key, $value) + { + return app()->instance($key, $value); + } + + public static function getAppKey($key) + { + if (app()->has($key)) { + return app()->get($key); + } + return null; + } + + public static function setRouteMap($data) + { + return self::setAppKey('dzq_boot_route_data', $data); + } + + public static function getRouteMap() + { + return self::getAppKey('dzq_boot_route_data'); + } + } diff --git a/src/Http/GroupCountBased.php b/src/Http/GroupCountBased.php new file mode 100644 index 0000000000000000000000000000000000000000..87c1222641cc90a1ec2e723b6a6ff3be58340490 --- /dev/null +++ b/src/Http/GroupCountBased.php @@ -0,0 +1,57 @@ +staticRouteMap, $this->variableRouteData) = $data; + } + + protected function dispatchVariableRoute($routeData, $uri) + { + foreach ($routeData as $data) { + if (!preg_match($data['regex'], $uri, $matches)) { + continue; + } + + list($handler, $varNames) = $data['routeMap'][count($matches)]; + + $vars = []; + $i = 0; + foreach ($varNames as $varName) { + $vars[$varName] = $matches[++$i]; + } + return [self::FOUND, $handler, $vars]; + } + + return [self::NOT_FOUND]; + } + + public function getStaticRouteMap() + { + return $this->staticRouteMap; + } + + public function getVariableRouteData() + { + return $this->variableRouteData; + } +} diff --git a/src/Http/Middleware/AuthenticateWithHeader.php b/src/Http/Middleware/AuthenticateWithHeader.php index e2800aeded838f7a6def5e54c94b4124c81f33ae..1fe257094c0e489a54a25c23a960cc0b66fe7382 100644 --- a/src/Http/Middleware/AuthenticateWithHeader.php +++ b/src/Http/Middleware/AuthenticateWithHeader.php @@ -18,16 +18,11 @@ namespace Discuz\Http\Middleware; -use App\Common\CacheKey; use App\Common\ResponseCode; -use App\Models\Setting; use App\Models\User; use App\Passport\Repositories\AccessTokenRepository; use Discuz\Auth\Guest; -use Discuz\Base\DzqLog; -use Discuz\Cache\CacheManager; use Discuz\Common\Utils; -use Discuz\Contracts\Setting\SettingsRepository; use Illuminate\Support\Arr; use League\OAuth2\Server\CryptKey; use League\OAuth2\Server\ResourceServer; @@ -38,250 +33,106 @@ use Psr\Http\Server\RequestHandlerInterface; class AuthenticateWithHeader implements MiddlewareInterface { - const AUTH_USER_CACHE_TTL = 300; - protected $cache; - - public function __construct(CacheManager $cache) - { - $this->cache = $cache; - } - - private $apiFreq = [ - 'get' => [ - 'freq' => 500, - 'forbidden' => 20 - ], - 'post' => [ - 'freq' => 100, - 'forbidden' => 30 - ] - ]; - - /** - * @param ServerRequestInterface $request - * @param RequestHandlerInterface $handler - * @return ResponseInterface - * @throws \League\OAuth2\Server\Exception\OAuthServerException - */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { - $api = Utils::getApiName(); - $this->getApiFreq($api); - - $headerLine = $request->getHeaderLine('authorization'); - if(empty($headerLine)){ //如果header头中没有 authorization,则从cookie里面找是否有access_token - $cookies = $request->getCookieParams(); - if(!empty($cookies['access_token'])){ - $headerLine = $cookies['access_token']; - $request = $request->withHeader('authorization', $headerLine); - } - } - - // 允许 get、cookie 携带 Token - if (!$headerLine) { - $headerLine = Arr::get($request->getQueryParams(), 'token'); - - if ($headerLine) { - $request = $request->withHeader('authorization', $headerLine); - } - } - - $request = $request->withAttribute('actor', new Guest()); + list($headerLine, $request) = $this->getHeaderLine($request); if ($headerLine) { $accessTokenRepository = new AccessTokenRepository(); - $publickey = new CryptKey(storage_path('cert/public.key'), '', false); - $server = new ResourceServer($accessTokenRepository, $publickey); - try { $request = $server->validateAuthenticatedRequest($request); - } catch (\Exception $e){ - $data = [ - 'api' => $api, - 'token' => $headerLine - ]; - DzqLog::error('invalid_token', $data, $e->getMessage()); + } catch (\Exception $e) { Utils::outPut(ResponseCode::INVALID_TOKEN); } - - $this->checkLimit($api, $request); + } + if ($this->isBadRequest($request)) throw new \Exception('操作太频繁,请稍后重试'); + if ($headerLine) { // 获取Token位置,根据 Token 解析用户并查询到当前用户 $actor = $this->getActor($request); - if (!is_null($actor) && $actor->exists) { $request = $request->withoutAttribute('oauth_access_token_id')->withoutAttribute('oauth_client_id')->withoutAttribute('oauth_user_id')->withoutAttribute('oauth_scopes')->withAttribute('actor', $actor); } - } else { - $this->checkLimit($api, $request); } return $handler->handle($request); } - private function getApiFreq($api) + private function getHeaderLine($request) { - $cache = app('cache'); - $cacheKey = CacheKey::API_FREQUENCE; - if ($api == 'cache.delete') { - $cache->forget($cacheKey); + $headerLine = $request->getHeaderLine('authorization'); + if (empty($headerLine)) { //如果header头中没有 authorization,则从cookie里面找是否有access_token + $cookies = $request->getCookieParams(); + if (!empty($cookies['access_token'])) { + $headerLine = $cookies['access_token']; + $request = $request->withHeader('authorization', $headerLine); + } } - $apiFreq = $cache->get($cacheKey); - if (!empty($apiFreq)) { - $this->apiFreq = json_decode($apiFreq, true); - } else { - $apiFreqSetting = Setting::query()->where('key', 'api_freq')->first(); - if (!empty($apiFreqSetting)) { - $this->apiFreq = json_decode($apiFreqSetting['value'], true); - $cache->put($cacheKey, $apiFreqSetting['value'], 5 * 60); + // 允许 get、cookie 携带 Token + if (!$headerLine) { + $headerLine = Arr::get($request->getQueryParams(), 'token'); + + if ($headerLine) { + $request = $request->withHeader('authorization', $headerLine); } } + //初始化为游客 + $request = $request->withAttribute('actor', new Guest()); + return [$headerLine, $request]; } + private function getActor(ServerRequestInterface $request) { $userId = $request->getAttribute('oauth_user_id'); if (!$userId) { return null; } - return $this->getActorFromDatabase($userId); - - //if (app()->config('middleware_cache')) { - /*$ttl = static::AUTH_USER_CACHE_TTL; - return $this->cache->remember( - CacheKey::AUTH_USER_PREFIX.$userId, - mt_rand($ttl, $ttl + 10), - function () use ($userId) { - return $this->getActorFromDatabase($userId); - } - );*/ - /*} else { - return $this->getActorFromDatabase($userId); - }*/ - } - - private function getActorFromDatabase($userId) - { - $actor = User::find($userId); - if (!is_null($actor) && $actor->exists) { - $actor->changeUpdateAt()->save(); - } + $cache = app('cache'); + $key = 'dzq_login_user_by_id_' . $userId; + $actor = $cache->get($key); + if (!$actor) { + $actor = User::find($userId); + $cache->put($key, $actor, 3 * 60); + } +// if (!is_null($actor) && $actor->exists) { +// $actor->changeUpdateAt()->save(); +// } return $actor; } - private function checkLimit($api, ServerRequestInterface $request) - { - $method = Arr::get($request->getServerParams(), 'REQUEST_METHOD', ''); - $userId = $request->getAttribute('oauth_user_id'); - if (strstr($api, 'backAdmin')) { - return; - } - if (strtolower($method) == 'get') { - if ($this->isForbidden($api, $userId, $request, $method, $this->apiFreq['get']['freq'])) { - throw new \Exception('操作太频繁,请稍后重试'); - } - } else { - if ($this->isForbidden($api, $userId, $request, $method, $this->apiFreq['post']['freq'])) { - throw new \Exception('操作太频繁,请稍后重试'); - } - } - } - private function isForbidden($api, $userId, ServerRequestInterface $request, $method, $max = 10, $interval = 60) + private function isBadRequest(ServerRequestInterface $request) { - - $ip = ip($request->getServerParams()); - if (empty($api)) { - return true; - } - $method = strtolower($method); - - if ($this->isAttachments($api, $method) || $this->isCoskey($api, $method)) { - $maxUploadNum = app()->make(SettingsRepository::class)->get('support_max_upload_attachment_num', 'default'); - $maxLimit = $maxUploadNum ? (int)$maxUploadNum : 20; + $api = $request->getUri()->getPath(); + if (Utils::startWith($api, '/backAdmin')) { + return false; } - + $httpMethod = Arr::get($request->getServerParams(), 'REQUEST_METHOD', ''); + $routeInfo = $this->getRouteInfo($api, $httpMethod); + $ip = ip($request->getServerParams()); + $userId = $request->getAttribute('oauth_user_id'); if (empty($userId)) { - $key = 'api_limit_by_ip_' . md5($ip . $api . $method); + $key = md5($ip . $api . $httpMethod); } else { - $key = 'api_limit_by_uid_' . md5($userId . '_' . $api . $method); - } - if ($this->isRegister($api, $method)) { - return $this->setLimit($key, $method, 10, 10 * 60); - } - if ($this->isAttachments($api, $method)) { - return $this->setLimit($key, $method, $maxLimit, 5 * 60); - } - if ($this->isPoll($api)) { - return $this->setLimit($key, $method, 200, 60); - } - - if ($this->isCoskey($api, $method)) { - return $this->setLimit($key, $method, $maxLimit, 30); + $key = md5($userId . $api . $httpMethod); } - if ($this->isPayOrder($api, $method)) { - return $this->setLimit($key, $method, 3, 10); + if($httpMethod == 'GET'){ + $times = $routeInfo['times'] ?: 20; + $interval = $routeInfo['interval'] ?: 30; + }else{ + $times = $routeInfo['times'] ?: 30; + $interval = $routeInfo['interval'] ?: 60; } - return $this->setLimit($key, $method, $max); - } - - private function isRegister($api, $method) - { - return $api == 'users/username.register' && $method == 'post'; - } - - private function isAttachments($api, $method) - { - return $api == 'attachments' && $method == 'post'; - } - - private function isPoll($api) - { - $pollapi = [ - 'users/pc/wechat/h5.login', - 'users/pc/wechat/h5.bind', - 'users/pc/wechat/miniprogram.bind', - 'users/pc/wechat/miniprogram.login', - 'users/pc/wechat.rebind.poll', - 'dialog/message', - 'unreadnotification', - 'dialog.update' - ]; - return in_array($api, $pollapi); - } - - private function isCoskey($api, $method) - { - return $api == 'coskey' && $method == 'post'; - } - - private function isPayOrder($api, $method){ - return $api == 'trade/pay/order' && $method == 'post'; - } - - /* - * $max interage 每分钟最大调用次数 - * $defaultDelay Boolen 超过调用次数禁止秒数 - */ - private function setLimit($key, $method, $max, $defaultDelay = null) - { + $delay = $routeInfo['delay'] ?: 300;//默认禁用5分钟 $cache = app('cache'); $count = $cache->get($key); - if (empty($count)) { - $cache->add($key, 1, 60); + $cache->add($key, 1, $interval); return false; } else { - if ($count >= $max) { - if ($defaultDelay == null) { - if ($method == 'get') { - $cache->put($key, $count, $this->apiFreq['get']['forbidden']); - } else { - $cache->put($key, $count, $this->apiFreq['post']['forbidden']); - } - } else { - $cache->put($key, $count, $defaultDelay); - } + if ($count >= $times) { + $cache->put($key, $count, $delay); return true; } else { $cache->increment($key); @@ -289,4 +140,50 @@ class AuthenticateWithHeader implements MiddlewareInterface } } } + + /** + * author: 流火行者 + * desc: 获取单个路由详情 + * @param $api + * @param $httpMethod + * @return bool + */ + private function getRouteInfo($api, $httpMethod) + { + $routeMaps = Utils::getRouteMap(); + $staticMaps = $routeMaps[0] ?? []; + $variableMaps = $routeMaps[1] ?? []; + foreach ($staticMaps as $method => $staticMap) { + if ($method == $httpMethod && isset($staticMap[$api])) return $staticMap[$api]; + } + foreach ($variableMaps as $method => $variableMap) { + $route = $this->dispatchVariableRoute($variableMap, $api); + if ($method == $httpMethod && $route) return $route; + } + return false; + } + + /** + * author: 流火行者 + * desc: 解析可变路由详情 + * @param $routeData + * @param $uri + * @return bool + */ + private function dispatchVariableRoute($routeData, $uri) + { + foreach ($routeData as $data) { + if (!preg_match($data['regex'], $uri, $matches)) { + continue; + } + list($handler, $varNames) = $data['routeMap'][count($matches)]; + $vars = []; + $i = 0; + foreach ($varNames as $varName) { + $vars[$varName] = $matches[++$i]; + } + return $handler; + } + return false; + } } diff --git a/src/Http/Middleware/DispatchRoute.php b/src/Http/Middleware/DispatchRoute.php index b145e1dd5ccde07cf345d12bd39dfb98690122e6..5b7ddcf8d6b3fd58249f9268d865af690ab1a65d 100644 --- a/src/Http/Middleware/DispatchRoute.php +++ b/src/Http/Middleware/DispatchRoute.php @@ -20,6 +20,7 @@ namespace Discuz\Http\Middleware; use Discuz\Http\Exception\MethodNotAllowedException; use Discuz\Http\Exception\RouteNotFoundException; +use Discuz\Http\GroupCountBased; use Discuz\Http\RouteCollection; use Discuz\Http\RouteHandlerFactory; use Psr\Http\Message\ResponseInterface; @@ -60,6 +61,7 @@ class DispatchRoute implements MiddlewareInterface * @param ServerRequestInterface $request * @param RequestHandlerInterface $handler * @return ResponseInterface + * @throws \Exception */ public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface { @@ -72,17 +74,42 @@ class DispatchRoute implements MiddlewareInterface case Dispatcher::METHOD_NOT_ALLOWED: throw new MethodNotAllowedException($method); case Dispatcher::FOUND: - $handler = $routeInfo[1]; + $handlerInfo = $routeInfo[1]; $parameters = $routeInfo[2]; + $handler = $this->getReplaceHandler($method, $handlerInfo); return $this->factory->toController($handler)($request, $parameters); } } protected function getDispatcher() { - if (! isset($this->dispatcher)) { - $this->dispatcher = new Dispatcher\GroupCountBased($this->routes->getRouteData()); + if (!isset($this->dispatcher)) { + $this->dispatcher = new GroupCountBased($this->routes->getRouteData()); } return $this->dispatcher; } + + protected function getReplaceHandler($method, $handlerInfo) + { + $dispatcher = $this->getDispatcher(); + $staticRouteMap = $dispatcher->getStaticRouteMap(); + //$variableRouteData = $dispatcher->getVariableRouteData(); //不支持动态路由 + $replaceHandlers = []; + foreach ($staticRouteMap as $m => $staticRoutes) { + foreach ($staticRoutes as $urlPath => $staticRoute) { + if(!empty($staticRoute['replaceHandler'])){ + $replaceHandlers[$staticRoute['replaceHandler']] = $staticRoute; + } + } + } + $handler = $handlerInfo['handler']; + if(isset($replaceHandlers[$handler])){ + if($replaceHandlers[$handler]['method'] == $method){ + return $replaceHandlers[$handler]['handler']; + }else{ + throw new \Exception('handler (' . $handler . ') method not matched'); + } + } + return $handler; + } } diff --git a/src/Http/RegexBasedAbstract.php b/src/Http/RegexBasedAbstract.php new file mode 100644 index 0000000000000000000000000000000000000000..86657f3ecc87f6a32dbe0868f2a70e0b20e240fb --- /dev/null +++ b/src/Http/RegexBasedAbstract.php @@ -0,0 +1,104 @@ +staticRouteMap[$httpMethod][$uri])) { + $handler = $this->staticRouteMap[$httpMethod][$uri]; + return [self::FOUND, $handler, []]; + } + + $varRouteData = $this->variableRouteData; + if (isset($varRouteData[$httpMethod])) { + $result = $this->dispatchVariableRoute($varRouteData[$httpMethod], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + + // For HEAD requests, attempt fallback to GET + if ($httpMethod === 'HEAD') { + if (isset($this->staticRouteMap['GET'][$uri])) { + $handler = $this->staticRouteMap['GET'][$uri]; + return [self::FOUND, $handler, []]; + } + if (isset($varRouteData['GET'])) { + $result = $this->dispatchVariableRoute($varRouteData['GET'], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + } + + // If nothing else matches, try fallback routes + if (isset($this->staticRouteMap['*'][$uri])) { + $handler = $this->staticRouteMap['*'][$uri]; + return [self::FOUND, $handler, []]; + } + if (isset($varRouteData['*'])) { + $result = $this->dispatchVariableRoute($varRouteData['*'], $uri); + if ($result[0] === self::FOUND) { + return $result; + } + } + + // Find allowed methods for this URI by matching against all other HTTP methods as well + $allowedMethods = []; + + foreach ($this->staticRouteMap as $method => $uriMap) { + if ($method !== $httpMethod && isset($uriMap[$uri])) { + $allowedMethods[] = $method; + } + } + + foreach ($varRouteData as $method => $routeData) { + if ($method === $httpMethod) { + continue; + } + + $result = $this->dispatchVariableRoute($routeData, $uri); + if ($result[0] === self::FOUND) { + $allowedMethods[] = $method; + } + } + + // If there are no allowed methods the route simply does not exist + if ($allowedMethods) { + return [self::METHOD_NOT_ALLOWED, $allowedMethods]; + } + + return [self::NOT_FOUND]; + } +} diff --git a/src/Http/RouteCollection.php b/src/Http/RouteCollection.php index 063e7c04085d41ab1f72db3e66e03f6e29e35108..c4ebfbeff40b40ae2f3763575c75e1867be279d8 100644 --- a/src/Http/RouteCollection.php +++ b/src/Http/RouteCollection.php @@ -40,38 +40,46 @@ class RouteCollection protected $currentGroupPrefix; + protected $times; + protected $interval; + protected $delay; + public function __construct() { $this->dataGenerator = new DataGenerator\GroupCountBased; + $this->routeParser = new RouteParser\Std; $this->currentGroupPrefix = ''; + $this->times = null; + $this->interval = null; + $this->delay = null; } - public function get($path, $name, $handler) - { - return $this->addRoute('GET', $path, $name, $handler); - } - - public function post($path, $name, $handler) - { - return $this->addRoute('POST', $path, $name, $handler); - } - - public function put($path, $name, $handler) + public function get($path, $name, $handler, $replaceHandler = null) { - return $this->addRoute('PUT', $path, $name, $handler); + return $this->addRoute('GET', $path, $name, $handler, $replaceHandler); } - public function patch($path, $name, $handler) + public function post($path, $name, $handler, $replaceHandler = null) { - return $this->addRoute('PATCH', $path, $name, $handler); + return $this->addRoute('POST', $path, $name, $handler, $replaceHandler); } - public function delete($path, $name, $handler) - { - return $this->addRoute('DELETE', $path, $name, $handler); - } +// public function put($path, $name, $handler) +// { +// return $this->addRoute('PUT', $path, $name, $handler); +// } +// +// public function patch($path, $name, $handler) +// { +// return $this->addRoute('PATCH', $path, $name, $handler); +// } +// +// public function delete($path, $name, $handler) +// { +// return $this->addRoute('DELETE', $path, $name, $handler); +// } public function group($prefix, callable $callback) { @@ -81,12 +89,37 @@ class RouteCollection $this->currentGroupPrefix = $previousGroupPrefix; } - public function addRoute($method, $path, $name, $handler) + /** + * @param callable $callback + * @param int $times 访问次数 + * @param int $interval 时间间隔(秒) + * @param int $delay 超过限频禁用时长(秒) + */ + public function withFrequency(callable $callback, $times = 100, $interval = 60, $delay = 300) + { + $this->times = $times; + $this->interval = $interval; + $this->delay = $delay; + $callback($this); + $this->times = null; + $this->interval = null; + $this->delay = null; + } + + public function addRoute($method, $path, $name, $handler, $replaceHandler = null) { $path = $this->currentGroupPrefix . $path; - $path = str_replace('//','/',$path); + $path = str_replace('//', '/', $path); $routeDatas = $this->routeParser->parse($path); foreach ($routeDatas as $routeData) { + $handler = [ + 'method' => $method, + 'handler' => $handler, + 'replaceHandler' => $replaceHandler, + 'times' => $this->times, + 'interval' => $this->interval, + 'delay' => $this->delay + ]; $this->dataGenerator->addRoute($method, $routeData, $handler); } @@ -111,7 +144,7 @@ class RouteCollection if (isset($this->reverse[$name])) { $parts = $this->reverse[$name][0]; array_walk($parts, [$this, 'fixPathPart'], $parameters); - return '/'.ltrim(implode('', $parts), '/'); + return '/' . ltrim(implode('', $parts), '/'); } throw new \RuntimeException("Route $name not found"); } diff --git a/src/Http/Server.php b/src/Http/Server.php index 593c5479945012a535d9332f0022ac682bd64108..8f162f56cf454890e2774985118a983c87d2f900 100644 --- a/src/Http/Server.php +++ b/src/Http/Server.php @@ -98,10 +98,12 @@ class Server extends SiteApp $line = $error->getLine(); $type = get_class($error); $this->app->make('log')->error($error); - + $trace = $error->getTraceAsString(); return << - thrown in $file on line $line + thrown in $file on line $line
+ $message
$trace + ERROR; } diff --git a/src/Web/WebServiceProvider.php b/src/Web/WebServiceProvider.php index cbf89a8555cfe9b3a29bcb0586c6611ed2014e9b..1cb3a07ff7acd32a9e4ff291b0e3a07a6835613d 100644 --- a/src/Web/WebServiceProvider.php +++ b/src/Web/WebServiceProvider.php @@ -18,6 +18,7 @@ namespace Discuz\Web; +use App\Common\Utils; use Discuz\Http\Middleware\DispatchRoute; use Discuz\Http\Middleware\HandleErrorsWithView; use Discuz\Http\Middleware\HandleErrorsWithWhoops; @@ -57,5 +58,7 @@ class WebServiceProvider extends ServiceProvider $route->group('', function (RouteCollection $route) { require $this->app->basePath('routes/web.php'); }); + \Discuz\Common\Utils::includePluginRoutes($route); + \Discuz\Common\Utils::setRouteMap($route->getRouteData()); } }