'update', // 更新资源,如:/users/ // 'DELETE {id}' => 'delete', // 删除资源,如:/users/ // 'GET,HEAD {id}' => 'view', // 查看资源单条数据,如:/users/ // 'POST' => 'create', // 新建资源,如:/users // 'GET,HEAD' => 'index', // 查看资源列表数据(可分页),如:/users // '{id}' => 'options', // 查看资源所支持的HTTP动词,如:/users/ | /users // '' => 'options', //]; /** * Route constructor. */ public function __construct() { parent::__construct(); $this->initRules(); } /** * HTTP请求解析 * * @param \swoole_http_request $request 请求对象 */ public function handleClientRequest($request) { $this->routePrams->path = rtrim($request->server['path_info'], '/'); $this->routePrams->verb = $this->parseVerb($request); $data = $this->parseRule(); // 如果未从rest配置中解析到,则按普通模式解析 $path = $data[0] ?? $this->routePrams->path; $this->parsePath($path); // 将 path 中含有的参数放入 get 中 if (!empty($data[1])) { foreach ($data[1] as $name => $value) { $request->get[$name] = $value; } } } /** * 解析路由规则 * * @return array */ public function parseRule() { if (empty($this->restRules)) { return []; } $pathInfo = $this->trimSlashes($this->routePrams->path); foreach ($this->restRules as $rule) { if (!in_array($this->routePrams->verb, $rule[0])) { continue; } if (!preg_match($rule[1][0], $pathInfo, $matches)) { continue; } $patternParams = $rule[1][1]; $pathParams = $rule[1][2]; $placeholders = $rule[1][3]; foreach ($placeholders as $placeholder => $name) { if (isset($matches[$placeholder])) { $matches[$name] = $matches[$placeholder]; unset($matches[$placeholder]); } } $params = []; $tr = []; foreach ($matches as $key => $value) { if (isset($pathParams[$key])) { $tr[$pathParams[$key]] = $value; //unset($params[$key]); $params[$key] = $value; } elseif (isset($patternParams[$key])) { $params[$key] = $value; } } $rule[2] = '/' . strtr($rule[2], $tr); return [$rule[2], $params]; } return []; } /** * 初始化Rules * * @return array|mixed */ protected function initRules() { $rules = getInstance()->config->get('rest.route.rules', []); if (empty($rules)) { return; } $verbs = 'GET|HEAD|POST|PUT|PATCH|DELETE|OPTIONS'; foreach ($rules as $pattern => $path) { // 分离 verb 和 pattern if (preg_match("/^((?:($verbs),)*($verbs))(?:\\s+(.*))?$/", $pattern, $matches1)) { $matchVerbs = explode(',', $matches1[1]); $pattern = isset($matches1[4]) ? $matches1[4] : ''; } else { $matchVerbs = []; } $patternParams = []; // pattern 里含有<> $pathParams = []; // path 里含有<> $placeholders = []; // pattern 预处理 $pattern = $this->trimSlashes($pattern); if ($pattern === '') { $pattern = '#^$#u'; $this->restRules[] = [ $matchVerbs, [$pattern, [], [], []], $path ]; continue; } else { $pattern = '/' . $pattern . '/'; } // 解析如果path里面含有<> if (strpos($path, '<') !== false && preg_match_all('/<([\w._-]+)>/', $path, $matches2)) { foreach ($matches2[1] as $name) { $pathParams[$name] = "<$name>"; } } // 解析如果pattern里面含有<> $tr = [ '.' => '\\.', '*' => '\\*', '$' => '\\$', '[' => '\\[', ']' => '\\]', '(' => '\\(', ')' => '\\)', ]; $tr2 = []; if (preg_match_all('/<([\w._-]+):?([^>]+)?>/', $pattern, $matches3, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) { foreach ($matches3 as $match) { $name = $match[1][0]; $tmpPattern = isset($match[2][0]) ? $match[2][0] : '[^\/]+'; $placeholder = 'a' . hash('crc32b', $name); $placeholders[$placeholder] = $name; $tr["<$name>"] = "(?P<$placeholder>$tmpPattern)"; if (isset($pathParams[$name])) { $tr2["<$name>"] = "(?P<$placeholder>$tmpPattern)"; } else { $patternParams[$name] = $tmpPattern === '[^\/]+' ? '' : "#^$tmpPattern$#u"; } } } $pattern = preg_replace('/<([\w._-]+):?([^>]+)?>/', '<$1>', $pattern); $pattern = '#^' . trim(strtr($pattern, $tr), '/') . '$#u'; // 组装数据 $this->restRules[] = [ $matchVerbs, [ $pattern, // 0 $patternParams, // 1 $pathParams, // 2 $placeholders // 3 ], $path ]; } } /** * 去掉下划线 * * @param string $string * @return string */ protected function trimSlashes($string) { if (strpos($string, '//') === 0) { return '//' . trim($string, '/'); } return trim($string, '/'); } }