mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 10:35:28 +08:00 
			
		
		
		
	decided to stick a basic cache in for downstream route creator, can make fancy if required (#359)
This commit is contained in:
		@@ -1,5 +1,6 @@
 | 
				
			|||||||
namespace Ocelot.DownstreamRouteFinder.Finder
 | 
					namespace Ocelot.DownstreamRouteFinder.Finder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using System.Collections.Concurrent;
 | 
				
			||||||
    using System.Collections.Generic;
 | 
					    using System.Collections.Generic;
 | 
				
			||||||
    using Configuration;
 | 
					    using Configuration;
 | 
				
			||||||
    using Configuration.Builder;
 | 
					    using Configuration.Builder;
 | 
				
			||||||
@@ -12,10 +13,12 @@
 | 
				
			|||||||
    public class DownstreamRouteCreator : IDownstreamRouteProvider
 | 
					    public class DownstreamRouteCreator : IDownstreamRouteProvider
 | 
				
			||||||
    {
 | 
					    {
 | 
				
			||||||
        private readonly IQoSOptionsCreator _qoSOptionsCreator;
 | 
					        private readonly IQoSOptionsCreator _qoSOptionsCreator;
 | 
				
			||||||
 | 
					        private readonly ConcurrentDictionary<string, OkResponse<DownstreamRoute>> _cache;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
 | 
					        public DownstreamRouteCreator(IQoSOptionsCreator qoSOptionsCreator)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _qoSOptionsCreator = qoSOptionsCreator;
 | 
					            _qoSOptionsCreator = qoSOptionsCreator;
 | 
				
			||||||
 | 
					            _cache = new ConcurrentDictionary<string, OkResponse<DownstreamRoute>>();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
 | 
					        public Response<DownstreamRoute> Get(string upstreamUrlPath, string upstreamHttpMethod, IInternalConfiguration configuration, string upstreamHost)
 | 
				
			||||||
@@ -33,6 +36,11 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
            var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);
 | 
					            var loadBalancerKey = CreateLoadBalancerKey(downstreamPathForKeys, upstreamHttpMethod, configuration.LoadBalancerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            if(_cache.TryGetValue(loadBalancerKey, out var downstreamRoute))
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return downstreamRoute;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new []{ upstreamHttpMethod });
 | 
					            var qosOptions = _qoSOptionsCreator.Create(configuration.QoSOptions, downstreamPathForKeys, new []{ upstreamHttpMethod });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
					            var downstreamReRoute = new DownstreamReRouteBuilder()
 | 
				
			||||||
@@ -51,7 +59,11 @@
 | 
				
			|||||||
                .WithUpstreamHttpMethod(new List<string>(){ upstreamHttpMethod })
 | 
					                .WithUpstreamHttpMethod(new List<string>(){ upstreamHttpMethod })
 | 
				
			||||||
                .Build();
 | 
					                .Build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute));
 | 
					            downstreamRoute = new OkResponse<DownstreamRoute>(new DownstreamRoute(new List<PlaceholderNameAndValue>(), reRoute));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            _cache.AddOrUpdate(loadBalancerKey, downstreamRoute, (x, y)  => downstreamRoute);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            return downstreamRoute;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static string RemoveQueryString(string downstreamPath)
 | 
					        private static string RemoveQueryString(string downstreamPath)
 | 
				
			||||||
@@ -67,12 +79,23 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        private static string GetDownstreamPath(string upstreamUrlPath)
 | 
					        private static string GetDownstreamPath(string upstreamUrlPath)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if(upstreamUrlPath.IndexOf('/', 1) == -1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return "/";
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return upstreamUrlPath
 | 
					            return upstreamUrlPath
 | 
				
			||||||
                .Substring(upstreamUrlPath.IndexOf('/', 1));
 | 
					                .Substring(upstreamUrlPath.IndexOf('/', 1));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private static string GetServiceName(string upstreamUrlPath)
 | 
					        private static string GetServiceName(string upstreamUrlPath)
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
 | 
					            if(upstreamUrlPath.IndexOf('/', 1) == -1)
 | 
				
			||||||
 | 
					            {
 | 
				
			||||||
 | 
					                return upstreamUrlPath
 | 
				
			||||||
 | 
					                    .Substring(1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return upstreamUrlPath
 | 
					            return upstreamUrlPath
 | 
				
			||||||
                .Substring(1, upstreamUrlPath.IndexOf('/', 1))
 | 
					                .Substring(1, upstreamUrlPath.IndexOf('/', 1))
 | 
				
			||||||
                .TrimEnd('/');
 | 
					                .TrimEnd('/');
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,6 +6,7 @@ using System.Net.Http;
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
					namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
 | 
					    using System;
 | 
				
			||||||
    using Moq;
 | 
					    using Moq;
 | 
				
			||||||
    using Ocelot.Configuration.Builder;
 | 
					    using Ocelot.Configuration.Builder;
 | 
				
			||||||
    using Ocelot.Configuration.Creator;
 | 
					    using Ocelot.Configuration.Creator;
 | 
				
			||||||
@@ -26,6 +27,7 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			|||||||
        private string _upstreamHttpMethod;
 | 
					        private string _upstreamHttpMethod;
 | 
				
			||||||
        private IInternalConfiguration _configuration;
 | 
					        private IInternalConfiguration _configuration;
 | 
				
			||||||
        private Mock<IQoSOptionsCreator> _qosOptionsCreator;
 | 
					        private Mock<IQoSOptionsCreator> _qosOptionsCreator;
 | 
				
			||||||
 | 
					        private Response<DownstreamRoute> _resultTwo;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        public DownstreamRouteCreatorTests()
 | 
					        public DownstreamRouteCreatorTests()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -50,6 +52,32 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_cache_downstream_route()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
 | 
				
			||||||
 | 
					                .When(_ => WhenICreate())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
 | 
				
			||||||
 | 
					                .When(_ => WhenICreateAgain())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheDownstreamRoutesAreTheSameReference())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_not_cache_downstream_route()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheConfiguration(configuration, "/geoffistheworst/"))
 | 
				
			||||||
 | 
					                .When(_ => WhenICreate())
 | 
				
			||||||
 | 
					                .And(_ => GivenTheConfiguration(configuration, "/geoffisthebest/"))
 | 
				
			||||||
 | 
					                .When(_ => WhenICreateAgain())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheDownstreamRoutesAreTheNotSameReference())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_create_downstream_route_with_no_path()
 | 
					        public void should_create_downstream_route_with_no_path()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -62,6 +90,30 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			|||||||
                .BDDfy();
 | 
					                .BDDfy();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_create_downstream_route_with_only_first_segment_no_traling_slash()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var upstreamUrlPath = "/auth";
 | 
				
			||||||
 | 
					            var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
 | 
				
			||||||
 | 
					                .When(_ => WhenICreate())
 | 
				
			||||||
 | 
					                .Then(_ => ThenTheDownstreamPathIsForwardSlash())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        [Fact]
 | 
				
			||||||
 | 
					        public void should_create_downstream_route_with_segments_no_traling_slash()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            var upstreamUrlPath = "/auth/test";
 | 
				
			||||||
 | 
					            var configuration = new InternalConfiguration(null, "doesnt matter", null, "doesnt matter", _loadBalancerOptions, "http", _qoSOptions, _handlerOptions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					            this.Given(_ => GivenTheConfiguration(configuration, upstreamUrlPath))
 | 
				
			||||||
 | 
					                .When(_ => WhenICreate())
 | 
				
			||||||
 | 
					                .Then(_ => ThenThePathDoesNotHaveTrailingSlash())
 | 
				
			||||||
 | 
					                .BDDfy();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        [Fact]
 | 
					        [Fact]
 | 
				
			||||||
        public void should_create_downstream_route_and_remove_query_string()
 | 
					        public void should_create_downstream_route_and_remove_query_string()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
@@ -143,6 +195,13 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			|||||||
            _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/|GET");
 | 
					            _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/|GET");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenThePathDoesNotHaveTrailingSlash()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
 | 
				
			||||||
 | 
					            _result.Data.ReRoute.DownstreamReRoute[0].ServiceName.ShouldBe("auth");
 | 
				
			||||||
 | 
					            _result.Data.ReRoute.DownstreamReRoute[0].LoadBalancerKey.ShouldBe("/auth/test|GET");
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        private void ThenTheQueryStringIsRemoved()
 | 
					        private void ThenTheQueryStringIsRemoved()
 | 
				
			||||||
        {
 | 
					        {
 | 
				
			||||||
            _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
 | 
					            _result.Data.ReRoute.DownstreamReRoute[0].DownstreamPathTemplate.Value.ShouldBe("/test");
 | 
				
			||||||
@@ -190,5 +249,20 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder
 | 
				
			|||||||
        {
 | 
					        {
 | 
				
			||||||
            _result = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
 | 
					            _result = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void WhenICreateAgain()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _resultTwo = _creator.Get(_upstreamUrlPath, _upstreamHttpMethod, _configuration, _upstreamHost);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheDownstreamRoutesAreTheSameReference()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.ShouldBe(_resultTwo);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        private void ThenTheDownstreamRoutesAreTheNotSameReference()
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					            _result.ShouldNotBe(_resultTwo);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user