Route.php 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | ThinkPHP [ WE CAN DO IT JUST THINK ]
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2006~2021 http://thinkphp.cn All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
  8. // +----------------------------------------------------------------------
  9. // | Author: liu21st <liu21st@gmail.com>
  10. // +----------------------------------------------------------------------
  11. declare (strict_types = 1);
  12. namespace think;
  13. use Closure;
  14. use think\exception\RouteNotFoundException;
  15. use think\route\Dispatch;
  16. use think\route\dispatch\Callback;
  17. use think\route\dispatch\Url as UrlDispatch;
  18. use think\route\Domain;
  19. use think\route\Resource;
  20. use think\route\Rule;
  21. use think\route\RuleGroup;
  22. use think\route\RuleItem;
  23. use think\route\RuleName;
  24. use think\route\Url as UrlBuild;
  25. /**
  26. * 路由管理类
  27. * @package think
  28. */
  29. class Route
  30. {
  31. /**
  32. * REST定义
  33. * @var array
  34. */
  35. protected $rest = [
  36. 'index' => ['get', '', 'index'],
  37. 'create' => ['get', '/create', 'create'],
  38. 'edit' => ['get', '/<id>/edit', 'edit'],
  39. 'read' => ['get', '/<id>', 'read'],
  40. 'save' => ['post', '', 'save'],
  41. 'update' => ['put', '/<id>', 'update'],
  42. 'delete' => ['delete', '/<id>', 'delete'],
  43. ];
  44. /**
  45. * 配置参数
  46. * @var array
  47. */
  48. protected $config = [
  49. // pathinfo分隔符
  50. 'pathinfo_depr' => '/',
  51. // 是否开启路由延迟解析
  52. 'url_lazy_route' => false,
  53. // 是否强制使用路由
  54. 'url_route_must' => false,
  55. // 合并路由规则
  56. 'route_rule_merge' => false,
  57. // 路由是否完全匹配
  58. 'route_complete_match' => false,
  59. // 去除斜杠
  60. 'remove_slash' => false,
  61. // 使用注解路由
  62. 'route_annotation' => false,
  63. // 默认的路由变量规则
  64. 'default_route_pattern' => '[\w\.]+',
  65. // URL伪静态后缀
  66. 'url_html_suffix' => 'html',
  67. // 访问控制器层名称
  68. 'controller_layer' => 'controller',
  69. // 空控制器名
  70. 'empty_controller' => 'Error',
  71. // 是否使用控制器后缀
  72. 'controller_suffix' => false,
  73. // 默认控制器名
  74. 'default_controller' => 'Index',
  75. // 默认操作名
  76. 'default_action' => 'index',
  77. // 操作方法后缀
  78. 'action_suffix' => '',
  79. // 非路由变量是否使用普通参数方式(用于URL生成)
  80. 'url_common_param' => true,
  81. ];
  82. /**
  83. * 当前应用
  84. * @var App
  85. */
  86. protected $app;
  87. /**
  88. * 请求对象
  89. * @var Request
  90. */
  91. protected $request;
  92. /**
  93. * @var RuleName
  94. */
  95. protected $ruleName;
  96. /**
  97. * 当前HOST
  98. * @var string
  99. */
  100. protected $host;
  101. /**
  102. * 当前分组对象
  103. * @var RuleGroup
  104. */
  105. protected $group;
  106. /**
  107. * 路由绑定
  108. * @var array
  109. */
  110. protected $bind = [];
  111. /**
  112. * 域名对象
  113. * @var Domain[]
  114. */
  115. protected $domains = [];
  116. /**
  117. * 跨域路由规则
  118. * @var RuleGroup
  119. */
  120. protected $cross;
  121. /**
  122. * 路由是否延迟解析
  123. * @var bool
  124. */
  125. protected $lazy = false;
  126. /**
  127. * 路由是否测试模式
  128. * @var bool
  129. */
  130. protected $isTest = false;
  131. /**
  132. * (分组)路由规则是否合并解析
  133. * @var bool
  134. */
  135. protected $mergeRuleRegex = false;
  136. /**
  137. * 是否去除URL最后的斜线
  138. * @var bool
  139. */
  140. protected $removeSlash = false;
  141. public function __construct(App $app)
  142. {
  143. $this->app = $app;
  144. $this->ruleName = new RuleName();
  145. $this->setDefaultDomain();
  146. if (is_file($this->app->getRuntimePath() . 'route.php')) {
  147. // 读取路由映射文件
  148. $this->import(include $this->app->getRuntimePath() . 'route.php');
  149. }
  150. $this->config = array_merge($this->config, $this->app->config->get('route'));
  151. $this->init();
  152. }
  153. protected function init()
  154. {
  155. if (!empty($this->config['middleware'])) {
  156. $this->app->middleware->import($this->config['middleware'], 'route');
  157. }
  158. $this->lazy($this->config['url_lazy_route']);
  159. $this->mergeRuleRegex = $this->config['route_rule_merge'];
  160. $this->removeSlash = $this->config['remove_slash'];
  161. $this->group->removeSlash($this->removeSlash);
  162. }
  163. public function config(string $name = null)
  164. {
  165. if (is_null($name)) {
  166. return $this->config;
  167. }
  168. return $this->config[$name] ?? null;
  169. }
  170. /**
  171. * 设置路由域名及分组(包括资源路由)是否延迟解析
  172. * @access public
  173. * @param bool $lazy 路由是否延迟解析
  174. * @return $this
  175. */
  176. public function lazy(bool $lazy = true)
  177. {
  178. $this->lazy = $lazy;
  179. return $this;
  180. }
  181. /**
  182. * 设置路由为测试模式
  183. * @access public
  184. * @param bool $test 路由是否测试模式
  185. * @return void
  186. */
  187. public function setTestMode(bool $test): void
  188. {
  189. $this->isTest = $test;
  190. }
  191. /**
  192. * 检查路由是否为测试模式
  193. * @access public
  194. * @return bool
  195. */
  196. public function isTest(): bool
  197. {
  198. return $this->isTest;
  199. }
  200. /**
  201. * 设置路由域名及分组(包括资源路由)是否合并解析
  202. * @access public
  203. * @param bool $merge 路由是否合并解析
  204. * @return $this
  205. */
  206. public function mergeRuleRegex(bool $merge = true)
  207. {
  208. $this->mergeRuleRegex = $merge;
  209. $this->group->mergeRuleRegex($merge);
  210. return $this;
  211. }
  212. /**
  213. * 初始化默认域名
  214. * @access protected
  215. * @return void
  216. */
  217. protected function setDefaultDomain(): void
  218. {
  219. // 注册默认域名
  220. $domain = new Domain($this);
  221. $this->domains['-'] = $domain;
  222. // 默认分组
  223. $this->group = $domain;
  224. }
  225. /**
  226. * 设置当前分组
  227. * @access public
  228. * @param RuleGroup $group 域名
  229. * @return void
  230. */
  231. public function setGroup(RuleGroup $group): void
  232. {
  233. $this->group = $group;
  234. }
  235. /**
  236. * 获取指定标识的路由分组 不指定则获取当前分组
  237. * @access public
  238. * @param string $name 分组标识
  239. * @return RuleGroup
  240. */
  241. public function getGroup(string $name = null)
  242. {
  243. return $name ? $this->ruleName->getGroup($name) : $this->group;
  244. }
  245. /**
  246. * 注册变量规则
  247. * @access public
  248. * @param array $pattern 变量规则
  249. * @return $this
  250. */
  251. public function pattern(array $pattern)
  252. {
  253. $this->group->pattern($pattern);
  254. return $this;
  255. }
  256. /**
  257. * 注册路由参数
  258. * @access public
  259. * @param array $option 参数
  260. * @return $this
  261. */
  262. public function option(array $option)
  263. {
  264. $this->group->option($option);
  265. return $this;
  266. }
  267. /**
  268. * 注册域名路由
  269. * @access public
  270. * @param string|array $name 子域名
  271. * @param mixed $rule 路由规则
  272. * @return Domain
  273. */
  274. public function domain($name, $rule = null): Domain
  275. {
  276. // 支持多个域名使用相同路由规则
  277. $domainName = is_array($name) ? array_shift($name) : $name;
  278. if (!isset($this->domains[$domainName])) {
  279. $domain = (new Domain($this, $domainName, $rule))
  280. ->lazy($this->lazy)
  281. ->removeSlash($this->removeSlash)
  282. ->mergeRuleRegex($this->mergeRuleRegex);
  283. $this->domains[$domainName] = $domain;
  284. } else {
  285. $domain = $this->domains[$domainName];
  286. $domain->parseGroupRule($rule);
  287. }
  288. if (is_array($name) && !empty($name)) {
  289. foreach ($name as $item) {
  290. $this->domains[$item] = $domainName;
  291. }
  292. }
  293. // 返回域名对象
  294. return $domain;
  295. }
  296. /**
  297. * 获取域名
  298. * @access public
  299. * @return array
  300. */
  301. public function getDomains(): array
  302. {
  303. return $this->domains;
  304. }
  305. /**
  306. * 获取RuleName对象
  307. * @access public
  308. * @return RuleName
  309. */
  310. public function getRuleName(): RuleName
  311. {
  312. return $this->ruleName;
  313. }
  314. /**
  315. * 设置路由绑定
  316. * @access public
  317. * @param string $bind 绑定信息
  318. * @param string $domain 域名
  319. * @return $this
  320. */
  321. public function bind(string $bind, string $domain = null)
  322. {
  323. $domain = is_null($domain) ? '-' : $domain;
  324. $this->bind[$domain] = $bind;
  325. return $this;
  326. }
  327. /**
  328. * 读取路由绑定信息
  329. * @access public
  330. * @return array
  331. */
  332. public function getBind(): array
  333. {
  334. return $this->bind;
  335. }
  336. /**
  337. * 读取路由绑定
  338. * @access public
  339. * @param string $domain 域名
  340. * @return string|null
  341. */
  342. public function getDomainBind(string $domain = null)
  343. {
  344. if (is_null($domain)) {
  345. $domain = $this->host;
  346. } elseif (false === strpos($domain, '.') && $this->request) {
  347. $domain .= '.' . $this->request->rootDomain();
  348. }
  349. if ($this->request) {
  350. $subDomain = $this->request->subDomain();
  351. if (strpos($subDomain, '.')) {
  352. $name = '*' . strstr($subDomain, '.');
  353. }
  354. }
  355. if (isset($this->bind[$domain])) {
  356. $result = $this->bind[$domain];
  357. } elseif (isset($name) && isset($this->bind[$name])) {
  358. $result = $this->bind[$name];
  359. } elseif (!empty($subDomain) && isset($this->bind['*'])) {
  360. $result = $this->bind['*'];
  361. } else {
  362. $result = null;
  363. }
  364. return $result;
  365. }
  366. /**
  367. * 读取路由标识
  368. * @access public
  369. * @param string $name 路由标识
  370. * @param string $domain 域名
  371. * @param string $method 请求类型
  372. * @return array
  373. */
  374. public function getName(string $name = null, string $domain = null, string $method = '*'): array
  375. {
  376. return $this->ruleName->getName($name, $domain, $method);
  377. }
  378. /**
  379. * 批量导入路由标识
  380. * @access public
  381. * @param array $name 路由标识
  382. * @return void
  383. */
  384. public function import(array $name): void
  385. {
  386. $this->ruleName->import($name);
  387. }
  388. /**
  389. * 注册路由标识
  390. * @access public
  391. * @param string $name 路由标识
  392. * @param RuleItem $ruleItem 路由规则
  393. * @param bool $first 是否优先
  394. * @return void
  395. */
  396. public function setName(string $name, RuleItem $ruleItem, bool $first = false): void
  397. {
  398. $this->ruleName->setName($name, $ruleItem, $first);
  399. }
  400. /**
  401. * 保存路由规则
  402. * @access public
  403. * @param string $rule 路由规则
  404. * @param RuleItem $ruleItem RuleItem对象
  405. * @return void
  406. */
  407. public function setRule(string $rule, RuleItem $ruleItem = null): void
  408. {
  409. $this->ruleName->setRule($rule, $ruleItem);
  410. }
  411. /**
  412. * 读取路由
  413. * @access public
  414. * @param string $rule 路由规则
  415. * @return RuleItem[]
  416. */
  417. public function getRule(string $rule): array
  418. {
  419. return $this->ruleName->getRule($rule);
  420. }
  421. /**
  422. * 读取路由列表
  423. * @access public
  424. * @return array
  425. */
  426. public function getRuleList(): array
  427. {
  428. return $this->ruleName->getRuleList();
  429. }
  430. /**
  431. * 清空路由规则
  432. * @access public
  433. * @return void
  434. */
  435. public function clear(): void
  436. {
  437. $this->ruleName->clear();
  438. if ($this->group) {
  439. $this->group->clear();
  440. }
  441. }
  442. /**
  443. * 注册路由规则
  444. * @access public
  445. * @param string $rule 路由规则
  446. * @param mixed $route 路由地址
  447. * @param string $method 请求类型
  448. * @return RuleItem
  449. */
  450. public function rule(string $rule, $route = null, string $method = '*'): RuleItem
  451. {
  452. if ($route instanceof Response) {
  453. // 兼容之前的路由到响应对象,感觉不需要,使用场景很少,闭包就能实现
  454. $route = function () use ($route) {
  455. return $route;
  456. };
  457. }
  458. return $this->group->addRule($rule, $route, $method);
  459. }
  460. /**
  461. * 设置跨域有效路由规则
  462. * @access public
  463. * @param Rule $rule 路由规则
  464. * @param string $method 请求类型
  465. * @return $this
  466. */
  467. public function setCrossDomainRule(Rule $rule, string $method = '*')
  468. {
  469. if (!isset($this->cross)) {
  470. $this->cross = (new RuleGroup($this))->mergeRuleRegex($this->mergeRuleRegex);
  471. }
  472. $this->cross->addRuleItem($rule, $method);
  473. return $this;
  474. }
  475. /**
  476. * 注册路由分组
  477. * @access public
  478. * @param string|\Closure $name 分组名称或者参数
  479. * @param mixed $route 分组路由
  480. * @return RuleGroup
  481. */
  482. public function group($name, $route = null): RuleGroup
  483. {
  484. if ($name instanceof Closure) {
  485. $route = $name;
  486. $name = '';
  487. }
  488. return (new RuleGroup($this, $this->group, $name, $route))
  489. ->lazy($this->lazy)
  490. ->removeSlash($this->removeSlash)
  491. ->mergeRuleRegex($this->mergeRuleRegex);
  492. }
  493. /**
  494. * 注册路由
  495. * @access public
  496. * @param string $rule 路由规则
  497. * @param mixed $route 路由地址
  498. * @return RuleItem
  499. */
  500. public function any(string $rule, $route): RuleItem
  501. {
  502. return $this->rule($rule, $route, '*');
  503. }
  504. /**
  505. * 注册GET路由
  506. * @access public
  507. * @param string $rule 路由规则
  508. * @param mixed $route 路由地址
  509. * @return RuleItem
  510. */
  511. public function get(string $rule, $route): RuleItem
  512. {
  513. return $this->rule($rule, $route, 'GET');
  514. }
  515. /**
  516. * 注册POST路由
  517. * @access public
  518. * @param string $rule 路由规则
  519. * @param mixed $route 路由地址
  520. * @return RuleItem
  521. */
  522. public function post(string $rule, $route): RuleItem
  523. {
  524. return $this->rule($rule, $route, 'POST');
  525. }
  526. /**
  527. * 注册PUT路由
  528. * @access public
  529. * @param string $rule 路由规则
  530. * @param mixed $route 路由地址
  531. * @return RuleItem
  532. */
  533. public function put(string $rule, $route): RuleItem
  534. {
  535. return $this->rule($rule, $route, 'PUT');
  536. }
  537. /**
  538. * 注册DELETE路由
  539. * @access public
  540. * @param string $rule 路由规则
  541. * @param mixed $route 路由地址
  542. * @return RuleItem
  543. */
  544. public function delete(string $rule, $route): RuleItem
  545. {
  546. return $this->rule($rule, $route, 'DELETE');
  547. }
  548. /**
  549. * 注册PATCH路由
  550. * @access public
  551. * @param string $rule 路由规则
  552. * @param mixed $route 路由地址
  553. * @return RuleItem
  554. */
  555. public function patch(string $rule, $route): RuleItem
  556. {
  557. return $this->rule($rule, $route, 'PATCH');
  558. }
  559. /**
  560. * 注册HEAD路由
  561. * @access public
  562. * @param string $rule 路由规则
  563. * @param mixed $route 路由地址
  564. * @return RuleItem
  565. */
  566. public function head(string $rule, $route): RuleItem
  567. {
  568. return $this->rule($rule, $route, 'HEAD');
  569. }
  570. /**
  571. * 注册OPTIONS路由
  572. * @access public
  573. * @param string $rule 路由规则
  574. * @param mixed $route 路由地址
  575. * @return RuleItem
  576. */
  577. public function options(string $rule, $route): RuleItem
  578. {
  579. return $this->rule($rule, $route, 'OPTIONS');
  580. }
  581. /**
  582. * 注册资源路由
  583. * @access public
  584. * @param string $rule 路由规则
  585. * @param string $route 路由地址
  586. * @return Resource
  587. */
  588. public function resource(string $rule, string $route): Resource
  589. {
  590. return (new Resource($this, $this->group, $rule, $route, $this->rest))
  591. ->lazy($this->lazy);
  592. }
  593. /**
  594. * 注册视图路由
  595. * @access public
  596. * @param string $rule 路由规则
  597. * @param string $template 路由模板地址
  598. * @param array $vars 模板变量
  599. * @return RuleItem
  600. */
  601. public function view(string $rule, string $template = '', array $vars = []): RuleItem
  602. {
  603. return $this->rule($rule, function () use ($vars, $template) {
  604. return Response::create($template, 'view')->assign($vars);
  605. }, 'GET');
  606. }
  607. /**
  608. * 注册重定向路由
  609. * @access public
  610. * @param string $rule 路由规则
  611. * @param string $route 路由地址
  612. * @param int $status 状态码
  613. * @return RuleItem
  614. */
  615. public function redirect(string $rule, string $route = '', int $status = 301): RuleItem
  616. {
  617. return $this->rule($rule, function (Request $request) use ($status, $route) {
  618. $search = $replace = [];
  619. $matches = $request->rule()->getVars();
  620. foreach ($matches as $key => $value) {
  621. $search[] = '<' . $key . '>';
  622. $replace[] = $value;
  623. $search[] = ':' . $key;
  624. $replace[] = $value;
  625. }
  626. $route = str_replace($search, $replace, $route);
  627. return Response::create($route, 'redirect')->code($status);
  628. }, '*');
  629. }
  630. /**
  631. * rest方法定义和修改
  632. * @access public
  633. * @param string|array $name 方法名称
  634. * @param array|bool $resource 资源
  635. * @return $this
  636. */
  637. public function rest($name, $resource = [])
  638. {
  639. if (is_array($name)) {
  640. $this->rest = $resource ? $name : array_merge($this->rest, $name);
  641. } else {
  642. $this->rest[$name] = $resource;
  643. }
  644. return $this;
  645. }
  646. /**
  647. * 获取rest方法定义的参数
  648. * @access public
  649. * @param string $name 方法名称
  650. * @return array|null
  651. */
  652. public function getRest(string $name = null)
  653. {
  654. if (is_null($name)) {
  655. return $this->rest;
  656. }
  657. return $this->rest[$name] ?? null;
  658. }
  659. /**
  660. * 注册未匹配路由规则后的处理
  661. * @access public
  662. * @param string|Closure $route 路由地址
  663. * @param string $method 请求类型
  664. * @return RuleItem
  665. */
  666. public function miss($route, string $method = '*'): RuleItem
  667. {
  668. return $this->group->miss($route, $method);
  669. }
  670. /**
  671. * 路由调度
  672. * @param Request $request
  673. * @param Closure|bool $withRoute
  674. * @return Response
  675. */
  676. public function dispatch(Request $request, $withRoute = true)
  677. {
  678. $this->request = $request;
  679. $this->host = $this->request->host(true);
  680. if ($withRoute) {
  681. //加载路由
  682. if ($withRoute instanceof Closure) {
  683. $withRoute();
  684. }
  685. $dispatch = $this->check();
  686. } else {
  687. $dispatch = $this->url($this->path());
  688. }
  689. $dispatch->init($this->app);
  690. return $this->app->middleware->pipeline('route')
  691. ->send($request)
  692. ->then(function () use ($dispatch) {
  693. return $dispatch->run();
  694. });
  695. }
  696. /**
  697. * 检测URL路由
  698. * @access public
  699. * @return Dispatch|false
  700. * @throws RouteNotFoundException
  701. */
  702. public function check()
  703. {
  704. // 自动检测域名路由
  705. $url = str_replace($this->config['pathinfo_depr'], '|', $this->path());
  706. $completeMatch = $this->config['route_complete_match'];
  707. $result = $this->checkDomain()->check($this->request, $url, $completeMatch);
  708. if (false === $result && !empty($this->cross)) {
  709. // 检测跨域路由
  710. $result = $this->cross->check($this->request, $url, $completeMatch);
  711. }
  712. if (false !== $result) {
  713. return $result;
  714. } elseif ($this->config['url_route_must']) {
  715. throw new RouteNotFoundException();
  716. }
  717. return $this->url($url);
  718. }
  719. /**
  720. * 获取当前请求URL的pathinfo信息(不含URL后缀)
  721. * @access protected
  722. * @return string
  723. */
  724. protected function path(): string
  725. {
  726. $suffix = $this->config['url_html_suffix'];
  727. $pathinfo = $this->request->pathinfo();
  728. if (false === $suffix) {
  729. // 禁止伪静态访问
  730. $path = $pathinfo;
  731. } elseif ($suffix) {
  732. // 去除正常的URL后缀
  733. $path = preg_replace('/\.(' . ltrim($suffix, '.') . ')$/i', '', $pathinfo);
  734. } else {
  735. // 允许任何后缀访问
  736. $path = preg_replace('/\.' . $this->request->ext() . '$/i', '', $pathinfo);
  737. }
  738. return $path;
  739. }
  740. /**
  741. * 默认URL解析
  742. * @access public
  743. * @param string $url URL地址
  744. * @return Dispatch
  745. */
  746. public function url(string $url): Dispatch
  747. {
  748. if ($this->request->method() == 'OPTIONS') {
  749. // 自动响应options请求
  750. return new Callback($this->request, $this->group, function () {
  751. return Response::create('', 'html', 204)->header(['Allow' => 'GET, POST, PUT, DELETE']);
  752. });
  753. }
  754. return new UrlDispatch($this->request, $this->group, $url);
  755. }
  756. /**
  757. * 检测域名的路由规则
  758. * @access protected
  759. * @return Domain
  760. */
  761. protected function checkDomain(): Domain
  762. {
  763. $item = false;
  764. if (count($this->domains) > 1) {
  765. // 获取当前子域名
  766. $subDomain = $this->request->subDomain();
  767. $domain = $subDomain ? explode('.', $subDomain) : [];
  768. $domain2 = $domain ? array_pop($domain) : '';
  769. if ($domain) {
  770. // 存在三级域名
  771. $domain3 = array_pop($domain);
  772. }
  773. if (isset($this->domains[$this->host])) {
  774. // 子域名配置
  775. $item = $this->domains[$this->host];
  776. } elseif (isset($this->domains[$subDomain])) {
  777. $item = $this->domains[$subDomain];
  778. } elseif (isset($this->domains['*.' . $domain2]) && !empty($domain3)) {
  779. // 泛三级域名
  780. $item = $this->domains['*.' . $domain2];
  781. $panDomain = $domain3;
  782. } elseif (isset($this->domains['*']) && !empty($domain2)) {
  783. // 泛二级域名
  784. if ('www' != $domain2) {
  785. $item = $this->domains['*'];
  786. $panDomain = $domain2;
  787. }
  788. }
  789. if (isset($panDomain)) {
  790. // 保存当前泛域名
  791. $this->request->setPanDomain($panDomain);
  792. }
  793. }
  794. if (false === $item) {
  795. // 检测全局域名规则
  796. $item = $this->domains['-'];
  797. }
  798. if (is_string($item)) {
  799. $item = $this->domains[$item];
  800. }
  801. return $item;
  802. }
  803. /**
  804. * URL生成 支持路由反射
  805. * @access public
  806. * @param string $url 路由地址
  807. * @param array $vars 参数 ['a'=>'val1', 'b'=>'val2']
  808. * @return UrlBuild
  809. */
  810. public function buildUrl(string $url = '', array $vars = []): UrlBuild
  811. {
  812. return $this->app->make(UrlBuild::class, [$this, $this->app, $url, $vars], true);
  813. }
  814. /**
  815. * 设置全局的路由分组参数
  816. * @access public
  817. * @param string $method 方法名
  818. * @param array $args 调用参数
  819. * @return RuleGroup
  820. */
  821. public function __call($method, $args)
  822. {
  823. return call_user_func_array([$this->group, $method], $args);
  824. }
  825. }