/// <summary>
        /// 获取请求信息
        /// </summary>
        private async Task <CustomRouteData> GetRequestData(HttpRequest request)
        {
            string requestBodyStr = "";

            using (var buffer = new MemoryStream())
            {
                await Request.Body.CopyToAsync(buffer);

                requestBodyStr = Encoding.UTF8.GetString(buffer.ToArray());
            }
            requestBody = requestBodyStr;

            //Get authorization information in the request headers, it needs  send to the micro service.
            authorizationHeadValue = Request.Headers[Const.HEAD_NAME_AUTHORIZATION];

            var requestHeadStr = Request.Headers[Const.HEAD_NAME_ROUTE_INFO];
            var requestHeadDic = HttpHelper.GetFormDictionary(requestHeadStr);

            requestHead = new RequestHead {
                BusinessCode = requestHeadDic["BusinessCode"], Ttl = Convert.ToInt32(requestHeadDic.GetValueOrDefault("Ttl", "0")), Channel = requestHeadDic.GetValueOrDefault("Channel", ""), Version = requestHeadDic.GetValueOrDefault("Version", "")
            };

            CustomRouteData route = routeHelper.GetOptimalRoute(requestHead.BusinessCode, requestHead.Version, requestHead.Channel);

            if (route == null)
            {
                throw new Exception("请求路由不存在");
            }
            return(route);
        }
        async Task <HttpResult> HandleRequest(CustomRouteData route)
        {
            HttpResult result = new HttpResult();
            int        expire = requestHead.Ttl.GetValueOrDefault();

            if (expire > 0 && route.Cache)
            {
                string key        = GeneralCacheKey();
                var    cacheValue = cache.Get(key);
                if (cacheValue != null)
                {
                    result.Content    = cacheValue.ToString();
                    result.HttpStatus = 200;
                    fromCache         = true;
                }
                else
                {
                    result = await HttpHelper.PostAsync(route.Handle, requestBody, authorizationHeadValue);

                    if (result.HttpStatus == 200)
                    {
                        cache.Set(key, result.Content, TimeSpan.FromSeconds(expire));
                    }
                    fromCache = false;
                }
            }
            else
            {
                result = await HttpHelper.PostAsync(route.Handle, requestBody, authorizationHeadValue);

                fromCache = false;
            }
            return(result);
        }
        public async Task <string> Post()
        {
            var routeSetting = await GetRequestData(Request);

            var requestResult = new HttpResult();

            if (routeSetting.RetryTimes > 0)
            {
                var policyHandle = Policy.HandleResult <HttpResult>(o => o.HttpStatus != 200)
                                   .RetryAsync(routeSetting.RetryTimes, (ex, count) =>
                {
                    logger.Error($"执行{routeSetting.BusinessCode}失败! 重试次数 {count}");
                    logger.Error($"异常来自 {ex.Result.Content},错误码 {ex.Result.HttpStatus}");
                });
                requestResult = await policyHandle.ExecuteAsync(() =>
                {
                    optimalRoute = GetLoadBalanceRoute(routeSetting);
                    logger.Debug($"begin request [{optimalRoute.Handle}],resquestHead:{ Request.Headers[Const.HEAD_NAME_ROUTE_INFO]} , requestBody:{requestBody} ,AuthorizationHead:{authorizationHeadValue}");
                    return(HandleRequest(optimalRoute));
                });

                logger.Debug($"end request [{optimalRoute.Handle}],from cache {fromCache.ToString()}");
            }
            else
            {
                optimalRoute  = GetLoadBalanceRoute(routeSetting);
                requestResult = await HandleRequest(optimalRoute);
            }

            if (requestResult.HttpStatus != 200)
            {
                Response.StatusCode = requestResult.HttpStatus;
            }
            return(requestResult.Content);
        }
Example #4
0
        /// <summary>
        /// 校验是否启用缓存
        /// </summary>
        /// <param name="userCache">请求启用缓存字段</param>
        /// <param name="channel">请求渠道</param>
        /// <param name="route">最优路由</param>
        /// <param name="body">请求参数</param>
        /// <returns></returns>
        protected bool CheckUseCache(bool?userCache, string channel, CustomRouteData route, Dictionary <string, object> body)
        {
            //启用缓存条件
            //- 请求Head参数UserCache:true
            //- 路由缓存时间配置大于0
            //- 渠道不为null,且渠道不在忽略的列表(IgnoreCacheChannel)中
            //- 满足请求条件,满足其一即可:
            //-- 请求Body无参数且路由缓存条件不存在
            //-- 请求body含参数且路由缓存存在条件且请求body所有非空字段都包含在路由缓存条件中

            if (!userCache.HasValue || userCache.Value == false)
            {
                return(false);
            }

            if (SettingsHelper.IgnoreCacheChannel(channel))
            {
                return(false);
            }
            if (route.CacheTime == 0)
            {
                return(false);
            }

            if (body == null || body.Count == 0)
            {
                return(true);
            }

            if (route.CacheCondition == null)
            {
                return(false);
            }

            List <Tuple <string, bool> > parms = new List <Tuple <string, bool> >();

            foreach (var p in body)
            {
                if (p.Value != null)
                {
                    string cValue = string.Empty;
                    if (!route.CacheCondition.TryGetValue(p.Key, out cValue))
                    {
                        cValue = string.Empty;
                    }
                    var parm = Tuple.Create(p.Key, cValue.Split(',').Contains(p.Value.ToString()));
                    parms.Add(parm);
                }
            }
            if (parms.Count(o => o.Item2 == true) == parms.Count)
            {
                return(true);
            }

            return(false);
        }
Example #5
0
        public BaseModule()
        {
            DateTime elapsedTime = DateTime.Now;
            bool     ignoreLog   = false;

            Before += ctx =>
            {
                var route = GetRequestData(ctx.Request);
                OptimalRoute           = route;
                HeadData.Authorization = RouteHelper.CreateToken(route);
                ignoreLog = SettingsHelper.IgnoreLogChannel(HeadData.Channel);
                return(null);
            };

            After += ctx =>
            {
                if (!ignoreLog)
                {
                    string response;
                    using (MemoryStream respData = new MemoryStream())
                    {
                        ctx.Response.Contents(respData);
                        response = Encoding.UTF8.GetString(respData.ToArray());
                    }

                    LogHelper.Info(HeadData.Command,
                                   string.Format(
                                       "Route request successfully,Address:{0},Time:{1}(s),Head:{2},Body:{3},RouteData:{4},Response:{5},UseCache:{6}",
                                       Request.Url, (DateTime.Now - elapsedTime).TotalSeconds, JsonConvert.SerializeObject(HeadData),
                                       JsonConvert.SerializeObject(BodyData), JsonConvert.SerializeObject(OptimalRoute), response,
                                       FinalUseCache));
                }
            };

            OnError += (ctx, ex) =>
            {
                if (!ignoreLog)
                {
                    LogHelper.Error(
                        string.Format("Route request Error,Command{0}", HeadData == null ? "" : HeadData.Command),
                        string.Format(
                            "Route request error,Address:{0},End time:{1},Head:{2},Body:{3},RouteData:{4},Error Message:{5}",
                            Request.Url, DateTime.Now, JsonConvert.SerializeObject(HeadData), JsonConvert.SerializeObject(BodyData),
                            JsonConvert.SerializeObject(OptimalRoute), ex.Message), ex);
                }
                dynamic response = new ExpandoObject();
                response.Code         = "500";
                response.ErrorMessage = string.Format("Route请求异常,Message:{0}", ex.Message);
                return(JsonConvert.SerializeObject(response));
            };
        }
        /// <summary>
        /// Instance Constructor
        /// </summary>
        public RouteViewService()
        {
            var componentParameters = new SortedDictionary <string, object>();

            componentParameters.Add("ID", 0);
            var route = new CustomRouteData()
            {
                PageType = typeof(Counter), RouteMatch = @"^\/counted\/(\d+)", ComponentParameters = componentParameters
            };

            Routes.Add(route);
            Routes.Add(new CustomRouteData()
            {
                PageType = typeof(Counter), RouteMatch = @"^\/counters"
            });
            Routes.Add(new CustomRouteData()
            {
                PageType = typeof(RouteViewer), RouteMatch = @"^\/routeviewer"
            });
        }
Example #7
0
        /// <summary>
        /// 路由负载均衡
        /// </summary>
        /// <param name="routeData"></param>
        /// <returns></returns>
        public CustomRouteData RoutingLoadBalance(
            CustomRouteData routeData)
        {
            var route = new CustomRouteData
            {
                BusinessCode = routeData.BusinessCode,
                MicroService = routeData.MicroService,
                Description  = routeData.Description,
                Channel      = routeData.Channel,
                Version      = routeData.Version
            };
            var hostData = GetHostDatas().FirstOrDefault(x => routeData.MicroService == x.MicroService);

            if (hostData != null)
            {
                var randomHost = RandomHelper.GetRandomList(hostData.Hosts.ToList(), 1).First();
                route.Handle = string.Concat(randomHost.ServiceUrl, routeData.Handle);
            }
            return(route);
        }
Example #8
0
        /// <summary>
        /// 获取请求信息
        /// </summary>
        private CustomRouteData GetRequestData(Request request)
        {
            //- Head
            var head = request.Headers["head"].FirstOrDefault();

            if (head == null)
            {
                throw new Exception("请求报文头数据不存在或格式不正确");
            }
            head     = Encoding.UTF8.GetString(EncodingHelper.Base64UrlDecode(head));
            HeadData = JsonConvert.DeserializeObject <RequestHead>(head);
            if (HeadData == null)
            {
                throw new Exception("请求报文头数据不存在");
            }
            if (string.IsNullOrEmpty(HeadData.Command))
            {
                throw new Exception("请求报文头指令名称不能为空");
            }
            //- Body
            var bodyForm = request.Form["body"];

            if (!string.IsNullOrWhiteSpace(bodyForm))
            {
                string key = SettingsHelper.GetDesKey(HeadData.Channel);
                bodyForm = EncryptHelper.DESDecrypt(bodyForm, key);
                string bodyStr = Encoding.UTF8.GetString(EncodingHelper.Base64UrlDecode(bodyForm));
                BodyData = JsonConvert.DeserializeObject <Dictionary <string, object> >(bodyStr);
            }
            //- Route
            CustomRouteData route = RouteHelper.GetOptimalRoute(HeadData.Command, HeadData.Version, HeadData.System);

            if (route == null)
            {
                throw new Exception("请求路由不存在");
            }

            route = RouteHelper.RoutingLoadBalance(route);

            return(route);
        }
Example #9
0
        /// <summary>
        /// 路由负载均衡
        /// </summary>
        /// <param name="routeData"></param>
        /// <returns></returns>
        public static CustomRouteData RoutingLoadBalance(
            CustomRouteData routeData)
        {
            var route = new CustomRouteData
            {
                CacheCondition = routeData.CacheCondition,
                CacheTime      = routeData.CacheTime,
                Command        = routeData.Command,
                MicroService   = routeData.MicroService,
                Name           = routeData.Name,
                System         = routeData.System,
                Version        = routeData.Version
            };
            var hostData = GetHostDatas().FirstOrDefault(x => routeData.MicroService == x.Name);

            if (hostData != null)
            {
                var randomHost = RandomHelper.GetRandomList(hostData.Hosts.ToList(), 1).First();
                route.Handle = string.Concat(randomHost.ServiceUrl, routeData.Handle);
            }
            return(route);
        }
Example #10
0
        public static string CreateToken(CustomRouteData route)
        {
            var host = GetHostDatas().First(o => o.Name == route.MicroService);
            IDateTimeProvider provider = new UtcDateTimeProvider();
            var now               = provider.GetNow();
            var unixEpoch         = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); // or use JwtValidator.UnixEpoch
            var secondsSinceEpoch = Math.Round((now - unixEpoch).TotalSeconds) + 60;     //60S后过期

            var payload = new Dictionary <string, object>
            {
                { "app_id", host.ApplicationId },
                { "exp", secondsSinceEpoch }
            };
            var secret = host.ApplicationKey;

            IJwtAlgorithm     algorithm  = new HMACSHA256Algorithm();
            IJsonSerializer   serializer = new JsonNetSerializer();
            IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
            IJwtEncoder       encoder    = new JwtEncoder(algorithm, serializer, urlEncoder);

            var token = encoder.Encode(payload, secret);

            return(token);
        }
Example #11
0
        /// <summary>
        /// 请求处理
        /// </summary>
        /// <param name="command">请求指令</param>
        /// <param name="head">请求报文头</param>
        /// <param name="route">最优路由</param>
        /// <param name="body">请求参数</param>
        /// <returns></returns>
        protected async Task <string> HandleRequest(string command, RequestHead head, CustomRouteData route, Dictionary <string, object> body)
        {
            string response;
            // 根据请求参数判断是否启用缓存
            // 启用-生成缓存KEY,并尝试读取缓存,成功则返回缓存值,失败则转发请求
            // 不启用-转发请求
            bool isUseCache = CheckUseCache(head.UseCache, head.Channel, route, body);

            if (isUseCache)
            {
                string key        = GeneralCacheKey(command, head.Version, head.System, route, body);
                var    cacheValue = CacheHelper.Get(key);
                if (cacheValue != null)
                {
                    response      = cacheValue;
                    FinalUseCache = true;
                }
                else
                {
                    response = await HttpClient.PostAsync(route.Handle, head, body);

                    CacheHelper.Set(key, response, new TimeSpan(0, 0, route.CacheTime));
                    FinalUseCache = false;
                }
            }
            else
            {
                response = await HttpClient.PostAsync(route.Handle, head, body);

                FinalUseCache = false;
            }

            return(response);
        }
Example #12
0
        /// <summary>
        /// 生成缓存Key
        /// </summary>
        /// <param name="command">请求命令</param>
        /// <param name="version">请求版本</param>
        /// <param name="system">请求系统</param>
        /// <param name="route">最优路由</param>
        /// <param name="body">请求参数</param>
        /// <returns></returns>
        protected string GeneralCacheKey(string command, string version, string system, CustomRouteData route, Dictionary <string, object> body)
        {
            // 缓存key格式:
            // home.banner_1.0.0_pc_condition1=value1_condition2=value2

            string key = string.Join("_", command, version, system);

            if (route.CacheCondition != null)
            {
                List <string> userCondition = new List <string>();
                foreach (var condition in route.CacheCondition)
                {
                    if (body != null && body.Keys.Contains(condition.Key, StringComparer.OrdinalIgnoreCase))
                    {
                        var bodyVal = body.First(x => string.Equals(x.Key, condition.Key, StringComparison.OrdinalIgnoreCase)).Value.ToString();
                        if (condition.Value.Contains(bodyVal))
                        {
                            string val = string.Format("{0}={1}", condition.Key, bodyVal);
                            userCondition.Add(val);
                        }
                    }
                }
                if (userCondition.Count > 0)
                {
                    key = string.Join("_", key, string.Join("_", userCondition.ToArray()));
                }
            }
            return(key.ToLower());
        }
 private CustomRouteData GetLoadBalanceRoute(CustomRouteData route)
 {
     return(routeHelper.RoutingLoadBalance(route));
 }