From 0d5613a33e1d3e6d25640fb4664ed4593b232989 Mon Sep 17 00:00:00 2001 From: daodao97 Date: Fri, 19 Jun 2020 14:49:25 +0800 Subject: [PATCH] =?UTF-8?q?perf:=20=E5=A2=9E=E5=8A=A0remote=20module=20?= =?UTF-8?q?=E8=AF=B7=E6=B1=82=E8=BD=AC=E5=8F=91=E6=A8=A1=E5=BC=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../components/business/cron-center.md | 9 +++- docs/backend/components/business/desc.md | 18 ++++++- src/admin/src/Controller/MenuController.php | 7 ++- src/admin/src/Controller/SystemController.php | 20 +++++-- .../src/Middleware/PermissionMiddleware.php | 27 ++++++++-- src/admin/src/Service/ModuleProxy.php | 52 +++++++++++++++++++ src/admin/src/Service/PermissionService.php | 3 +- src/admin/src/config/routes.php | 1 + src/base-utils/src/Guzzle.php | 48 +++++++++++++++++ 9 files changed, 171 insertions(+), 14 deletions(-) create mode 100644 src/admin/src/Service/ModuleProxy.php diff --git a/docs/backend/components/business/cron-center.md b/docs/backend/components/business/cron-center.md index 7f41689..ccd0fc8 100644 --- a/docs/backend/components/business/cron-center.md +++ b/docs/backend/components/business/cron-center.md @@ -4,4 +4,11 @@ 作业必须基于`App\Util\CronCenter\ClassJobAbstract`, 或`App/Util/CronCenter/CommandJobAbstract.php`抽象类进行实现, 才可进行执行状态的跟踪 -`CronCenter`的实现基于`hyperf-crontab`进行实现, 具体代码在`app/Util/CronCenter`, 更多细节可查看[文档](https://hyperf.wiki/#/zh-cn/crontab) +`CronCenter`的实现基于`hyperf-crontab`进行实现, 具体代码在`src/CronCenter`, 更多细节可查看[文档](https://hyperf.wiki/#/zh-cn/crontab) + +开启`cron-center` `config/autoload/crontab.php` +```php +[ + "enable" => true +] +``` diff --git a/docs/backend/components/business/desc.md b/docs/backend/components/business/desc.md index 2fa4033..bf547a3 100644 --- a/docs/backend/components/business/desc.md +++ b/docs/backend/components/business/desc.md @@ -68,4 +68,20 @@ php bin/hyperf.php 然后将相应的菜单添加到后台即可使用. -!> 这里的组件菜单, 后期可以优化成配置文件导入的方式, 会更简单些 \ No newline at end of file +!> 这里的组件菜单, 后期可以优化成配置文件导入的方式, 会更简单些 + +业务组件的db依赖问题, 参见 `src/cron-center/src/ConfigProvider.php` 中 `databases` + +```php +'databases' => [ + 'config_center' => db_complete([ + 'host' => env('CONFIG_CENTER_DB_HOST', env('HYPERF_ADMIN_DB_HOST')), + 'database' => env('CONFIG_CENTER_DB_NAME', env('HYPERF_ADMIN_DB_NAME')), + 'username' => env('CONFIG_CENTER_DB_USER', env('HYPERF_ADMIN_DB_USER')), + 'password' => env('CONFIG_CENTER_DB_PWD', env('HYPERF_ADMIN_DB_PWD')), + ]), +], +``` + +组件可以使用自己单独的库配置, 默认使用 `hyperf_amdin` 的主db配置. + diff --git a/src/admin/src/Controller/MenuController.php b/src/admin/src/Controller/MenuController.php index 88af348..85916ea 100644 --- a/src/admin/src/Controller/MenuController.php +++ b/src/admin/src/Controller/MenuController.php @@ -194,11 +194,9 @@ class MenuController extends AdminAbstractController 'permission|权限标识' => [ 'type' => 'select', 'default' => [], - 'options' => function ($field, $data) { - return $this->permission_service->getSystemRouteOptions(); - }, 'props' => [ 'multiple' => true, + 'selectApi' => '/system/routes?module={module}' ], ], 'pid|上级类目' => [ @@ -272,7 +270,7 @@ class MenuController extends AdminAbstractController [ 'text' => '加子菜单', 'type' => 'form', - 'target' => '/menu/form?pid[]={id}&module={tab_id}', + 'target' => '/menu/form?pid[]={id}&module={module}', 'formUi' => [ 'form' => [ 'labelWidth' => '80px', @@ -330,6 +328,7 @@ class MenuController extends AdminAbstractController 'columns' => [ ['field' => 'id', 'hidden' => true], ['field' => 'pid', 'hidden' => true], + ['field' => 'module', 'hidden' => true], [ 'field' => 'label', 'width' => '250px', diff --git a/src/admin/src/Controller/SystemController.php b/src/admin/src/Controller/SystemController.php index 6f9f504..81be74c 100644 --- a/src/admin/src/Controller/SystemController.php +++ b/src/admin/src/Controller/SystemController.php @@ -1,10 +1,9 @@ success($config); } + + public function routes() + { + $module_proxy = make(ModuleProxy::class); + if ($module_proxy->needProxy()) { + return $this->success($module_proxy->request()['payload']); + } + + $kw = $this->request->input('kw', ''); + $routes = $this->permission_service->getSystemRouteOptions(); + $routes = array_filter($routes, function ($item) use ($kw) { + return Str::contains($item['value'], $kw); + }); + return $this->success(array_values($routes)); + } } diff --git a/src/admin/src/Middleware/PermissionMiddleware.php b/src/admin/src/Middleware/PermissionMiddleware.php index 9e06b96..8dea4fe 100644 --- a/src/admin/src/Middleware/PermissionMiddleware.php +++ b/src/admin/src/Middleware/PermissionMiddleware.php @@ -5,18 +5,25 @@ */ namespace HyperfAdmin\Admin\Middleware; +use FastRoute\Dispatcher; use Hyperf\HttpServer\Contract\RequestInterface; use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse; use Hyperf\HttpServer\CoreMiddleware; +use Hyperf\HttpServer\Router\Dispatched; use Hyperf\Logger\LoggerFactory; +use HyperfAdmin\Admin\Service\AuthService; +use HyperfAdmin\Admin\Service\CommonConfig; +use HyperfAdmin\Admin\Service\ModuleProxy; +use HyperfAdmin\Admin\Service\PermissionService; +use HyperfAdmin\BaseUtils\AKSK; +use HyperfAdmin\BaseUtils\Constants\ErrorCode; +use HyperfAdmin\BaseUtils\Guzzle; +use HyperfAdmin\BaseUtils\Log; +use HyperfAdmin\BaseUtils\Redis\Redis; use Psr\Container\ContainerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Psr\Http\Server\RequestHandlerInterface; -use HyperfAdmin\Admin\Service\PermissionService; -use HyperfAdmin\Admin\Service\AuthService; -use HyperfAdmin\BaseUtils\AKSK; -use HyperfAdmin\BaseUtils\Constants\ErrorCode; class PermissionMiddleware extends CoreMiddleware { @@ -61,6 +68,18 @@ class PermissionMiddleware extends CoreMiddleware $uri = $request->getUri(); $path = $uri->getPath(); $method = $request->getMethod(); + + $module_proxy = make(ModuleProxy::class); + if ($module_proxy->needProxy()) { + $res = $module_proxy->request(); + if(isset($res['payload']) && $res['payload'] === []) { + $res['payload'] = (object)[]; + } + $response = $this->response->json($res); + Log::get('http')->info('proxy_end', ['module' => $module_proxy->getTargetModule(), 'path' => $path, 'response' => $response]); + return $response; + } + // 其他系统调用,走AKSK中间件验证 $client_token = $request->getHeader('Authorization')[0] ?? ''; if ($client_token) { diff --git a/src/admin/src/Service/ModuleProxy.php b/src/admin/src/Service/ModuleProxy.php new file mode 100644 index 0000000..6354309 --- /dev/null +++ b/src/admin/src/Service/ModuleProxy.php @@ -0,0 +1,52 @@ +request = request(); + $this->modules = Redis::getOrSet('hyperf_admin:system_modules', 500, function () { + $list = CommonConfig::getConfigByName('website_config')['value']['system_module']; + array_change_v2k($list, 'name'); + return $list; + }); + $this->target_module = $this->request->input('module') ?? (request_header('x-module')[0] ?? ''); + } + + public function needProxy() + { + $no_proxy = request_header('x-no-proxy')[0] ?? false; + + if ($no_proxy) { + return false; + } + + if (!isset($this->modules[$this->target_module])) { + return false; + } + + if ($this->modules[$this->target_module]['type'] != 'remote') { + return false; + } + + return true; + } + + public function request() + { + return Guzzle::proxy($this->modules[$this->target_module]['remote_base_uri'] . $this->request->getUri()->getPath(), $this->request); + } + + public function getTargetModule() + { + return $this->target_module; + } +} diff --git a/src/admin/src/Service/PermissionService.php b/src/admin/src/Service/PermissionService.php index 54ca976..a24a661 100644 --- a/src/admin/src/Service/PermissionService.php +++ b/src/admin/src/Service/PermissionService.php @@ -243,7 +243,8 @@ class PermissionService } } $user_open_apis = $this->getOpenResourceList('user_open_api'); - return array_merge($resources, $user_open_apis); + $system_user_open = config('system.user_open_resource', ['/system/routes']); + return array_merge($resources, $user_open_apis, $system_user_open); } public function getOpenResourceList($field = 'open_api') diff --git a/src/admin/src/config/routes.php b/src/admin/src/config/routes.php index c773d1c..0673e0f 100644 --- a/src/admin/src/config/routes.php +++ b/src/admin/src/config/routes.php @@ -38,3 +38,4 @@ register_route('/cconf', CommonConfigController::class, function ($controller) { }); Router::get('/system/config', [SystemController::class, 'config']); +Router::get('/system/routes', [SystemController::class, 'routes']); diff --git a/src/base-utils/src/Guzzle.php b/src/base-utils/src/Guzzle.php index 10c1184..95375b5 100644 --- a/src/base-utils/src/Guzzle.php +++ b/src/base-utils/src/Guzzle.php @@ -3,6 +3,8 @@ namespace HyperfAdmin\BaseUtils; use GuzzleHttp\Client; use Hyperf\Guzzle\ClientFactory; +use Psr\Http\Message\ServerRequestInterface; +use GuzzleHttp\Cookie\CookieJar; class Guzzle { @@ -76,4 +78,50 @@ class Guzzle return false; } } + + public static function proxy($url, ServerRequestInterface $request) + { + $client = self::create([ + 'timeout' => 10.0, + ]); + + $options = []; + + $logger = Log::get('module_proxy'); + + try { + $options['headers']['X-No-Proxy'] = true; + + $options['headers'] = array_merge($options['headers'], array_map(function ($item) { + return $item[0]; + }, request_header())); + + $parse =parse_url($url); + $domain = isset($parse['port']) ? $parse['host'] . ':' . $parse['port'] : $parse['host']; + $options['cookies'] = CookieJar::fromArray(cookie(), $domain); + + if ($query = $request->getQueryParams()) { + $options['query'] = $query; + } + if ($body = (array)json_decode($request->getBody()->getContents(), true)) { + $options['body'] = \GuzzleHttp\json_encode($body); + } + if ($form_data = $request->getParsedBody()) { + $options['form_params'] = $form_data; + } + + $request = retry(3, function () use ($client, $request, $url, $options) { + return $client->request($request->getMethod(), $url, $options); + }, 50); + $content = $request->getBody()->getContents(); + $logger->info('proxy_success', compact('url', 'options')); + return my_json_decode($content); + } catch (\GuzzleHttp\Exception\GuzzleException $e) { + $logger->error('proxy_fail', compact('url', 'options', 'e')); + throw new \Exception("proxy exception {$e}", 500); + } catch (\Throwable $e) { + $logger->error('proxy_fail', compact('url', 'options', 'e')); + throw new \Exception("proxy exception {$e}", 500); + } + } }