Symfony 5白标路由动态处理方案技术咨询
Symfony 5 动态白标(Whitelabel)路由解决方案
方案一:自定义路由加载器(推荐,适配Bundle架构)
通过扩展Symfony的路由加载机制,自动为每个白标复制主路由并生成带前缀的路由,支持从配置或数据库动态获取白标列表,无需硬编码。
步骤1:创建自定义RouteLoader
在你的Bundle中实现路由加载器类:
// src/YourBundle/Loader/WhitelabelRouteLoader.php namespace YourBundle\Loader; use Symfony\Component\Config\Loader\LoaderInterface; use Symfony\Component\Config\Loader\LoaderResolverInterface; use Symfony\Component\Routing\Route; use Symfony\Component\Routing\RouteCollection; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; use Symfony\Component\Routing\Loader\AnnotationClassLoader; use Symfony\Component\Routing\Annotation\RouteAnnotationReader; class WhitelabelRouteLoader implements LoaderInterface { private $loaded = false; private $params; public function __construct(ParameterBagInterface $params) { $this->params = $params; } public function load($resource, $type = null) { if ($this->loaded) { throw new \RuntimeException('该加载器已执行过加载操作'); } $routeCollection = new RouteCollection(); // 加载主控制器的注解路由 $mainRoutes = $this->importMainRoutes(); // 从配置获取白标列表(可替换为数据库查询逻辑) $whitelabels = $this->params->get('your_bundle.whitelabels'); // 为每个白标生成对应路由 foreach ($whitelabels as $label) { foreach ($mainRoutes as $routeName => $route) { if (str_starts_with($routeName, 'mainlabel_')) { $newRouteName = str_replace('mainlabel_', "{$label}_", $routeName); // 生成白标路由路径,可根据需求调整格式 $newPath = "/{$label}" . preg_replace('#^/mainlabel#', '', $route->getPath()); $newRoute = clone $route; $newRoute->setPath($newPath); $newRoute->setDefault('whitelabel', $label); $routeCollection->add($newRouteName, $newRoute); } } } $this->loaded = true; return $routeCollection; } private function importMainRoutes() { $loader = new AnnotationClassLoader(new RouteAnnotationReader()); // 替换为你的主控制器目录 return $loader->load(__DIR__ . '/../Controller/MainController.php'); } public function supports($resource, $type = null) { return $type === 'whitelabel'; } public function getResolver() { return null; } public function setResolver(LoaderResolverInterface $resolver) {} }
步骤2:注册路由加载器
在Bundle的services.yaml中配置:
# src/YourBundle/Resources/config/services.yaml services: YourBundle\Loader\WhitelabelRouteLoader: arguments: $params: '@parameter_bag' tags: - { name: routing.loader }
步骤3:配置白标列表
在Bundle配置文件中添加白标配置:
# config/packages/your_bundle.yaml your_bundle: whitelabels: ['whitelabel_alpha', 'whitelabel_beta', 'whitelabel_gamma']
步骤4:加载自定义路由
在config/routes.yaml中引入:
# config/routes.yaml your_bundle_whitelabel_routes: resource: . type: whitelabel
方案二:动态路由前缀+请求事件监听
无需生成大量路由,通过统一前缀占位符+事件验证白标合法性,适合路由数量较多的场景。
步骤1:添加带白标前缀的路由
修改主控制器的路由注解:
// src/YourBundle/Controller/MainController.php /** * @Route("/{whitelabel}/test", name="whitelabel_test") * @Route("/mainlabel/test", name="mainlabel_test") * @return Response */ public function test(Request $request, string $whitelabel = null) { if ($whitelabel) { // 处理白标专属逻辑 } // 原有业务逻辑 }
步骤2:创建请求事件监听器
验证白标合法性:
// src/YourBundle/EventListener/WhitelabelListener.php namespace YourBundle\EventListener; use Symfony\Component\HttpKernel\Event\RequestEvent; use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; use Symfony\Component\DependencyInjection\ParameterBag\ParameterBagInterface; class WhitelabelListener { private $params; public function __construct(ParameterBagInterface $params) { $this->params = $params; } public function onKernelRequest(RequestEvent $event) { $request = $event->getRequest(); $whitelabel = $request->get('whitelabel'); if (!$whitelabel) return; $validWhitelabels = $this->params->get('your_bundle.whitelabels'); if (!in_array($whitelabel, $validWhitelabels)) { throw new NotFoundHttpException('无效的白标标识'); } // 将白标信息存入请求属性,供后续控制器使用 $request->attributes->set('whitelabel', $whitelabel); } }
步骤3:注册事件监听器
# src/YourBundle/Resources/config/services.yaml services: YourBundle\EventListener\WhitelabelListener: arguments: $params: '@parameter_bag' tags: - { name: kernel.event_listener, event: kernel.request, method: onKernelRequest }
解决现有转发方案的问题:通过路由名获取控制器
如果坚持使用转发控制器,可通过RouterInterface获取路由对应的控制器信息:
use Symfony\Component\Routing\RouterInterface; use Symfony\Component\Routing\Exception\RouteNotFoundException; // 在控制器中注入RouterInterface public function whitelabelForward(Request $request, RouterInterface $router) { $whitelabel = $request->attributes->get('whitelabel'); $action = $request->attributes->get('action'); $id = $request->attributes->get('id'); $mainRouteName = 'mainlabel' . ($action ? "_$action" : ''); $params = $id ? ['id' => $id] : []; try { $route = $router->getRouteCollection()->get($mainRouteName); if (!$route) throw new RouteNotFoundException(); $controllerStr = $route->getDefault('_controller'); // 解析控制器字符串 if (is_array($controllerStr)) { [$controllerClass, $controllerMethod] = $controllerStr; } else { [$controllerClass, $controllerMethod] = explode('::', $controllerStr); } return $this->forward("$controllerClass::$controllerMethod", array_merge($params, [ 'whitelabel' => $whitelabel, ])); } catch (RouteNotFoundException $e) { throw new NotFoundHttpException(); } }
注意:生产环境路由集合会被缓存,新增白标后需执行
bin/console cache:clear清除缓存。
内容的提问来源于stack exchange,提问作者StevieStef
相关产品推荐
相关产品推荐

