public bool Match(HttpRequest request, out RouteMatchResult result, QueryString queryString)
        {
            result = null;
            RouteGroup rg       = null;
            UrlRoute   urlRoute = null;
            string     key      = $"{request.GetHostBase()}{request.BaseUrl}";

            if (mRouteCached.TryGetValue(key, out UrlRouteAgent cached))
            {
                cached.ActiveTime = TimeWatch.GetTotalSeconds();
                if (cached.Route == null && cached.Version == this.mVersion)
                {
                    if (request.Server.EnableLog(EventArgs.LogType.Info))
                    {
                        request.Server.Log(EventArgs.LogType.Info, $"HTTP {request.ID} {request.RemoteIPAddress} {request.Method} {key} rewrite cached miss");
                    }
                    return(false);
                }
                if (cached.Route != null && cached.Version == this.mVersion)
                {
                    if (cached.Parameters.Count > 0)
                    {
                        foreach (var item in cached.Parameters)
                        {
                            queryString.Add(item.Key, item.Value);
                        }
                    }
                    result = cached.MatchResult;
                    if (request.Server.EnableLog(EventArgs.LogType.Info))
                    {
                        request.Server.Log(EventArgs.LogType.Info, $"HTTP {request.ID} {request.RemoteIPAddress} {request.Method} {key} rewrite cached hit");
                    }
                    return(true);
                }
            }
            bool iscached = true;
            Dictionary <string, string> parameters = new Dictionary <string, string>();

            result = new RouteMatchResult();
            if (mRoutes.TryGetValue(request.Path, out rg))
            {
                urlRoute = rg.Match(request.BaseUrl, ref result, parameters, request.Ext, request);
            }
            if (urlRoute == null)
            {
                RouteGroup[] rgs = mMatchRoutes;
                if (rgs != null)
                {
                    for (int i = 0; i < rgs.Length; i++)
                    {
                        rg = rgs[i];
                        if (rg.PathLevel == request.PathLevel)
                        {
                            iscached = rg.Cached;
                            urlRoute = rg.Match(request.BaseUrl, ref result, parameters, request.Ext, request);
                            if (urlRoute != null)
                            {
                                if (urlRoute.Prefix != null && urlRoute.Prefix.Type == UrlPrefix.PrefixType.Host)
                                {
                                    iscached = true;
                                }
                                break;
                            }
                        }
                    }
                }
            }
            if (urlRoute != null)
            {
                result.HasQueryString = urlRoute.HasQueryString;
            }
            if (urlRoute != null && urlRoute.Prefix?.Type == UrlPrefix.PrefixType.Param)
            {
                return(urlRoute != null);
            }
            var agent = new UrlRouteAgent {
                Route = urlRoute, Version = this.mVersion, MatchResult = result, Parameters = parameters
            };

            if (parameters.Count > 0)
            {
                foreach (var ps in parameters)
                {
                    queryString.Add(ps.Key, ps.Value);
                }
            }
            if (iscached)
            {
                UrlRouteAgent exits = (UrlRouteAgent)mRouteCached.ExistOrAdd(key, agent);
                if (request.Server.EnableLog(EventArgs.LogType.Info))
                {
                    request.Server.Log(EventArgs.LogType.Info, $"HTTP {request.ID} {request.RemoteIPAddress} {request.Method} {key} rewrite save to cached");
                }
                if (exits != null)
                {
                    exits.Route       = urlRoute;
                    exits.Version     = mVersion;
                    exits.MatchResult = result;
                    exits.Parameters  = parameters;
                }
            }
            return(urlRoute != null);
        }