mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 01:18:15 +08:00
Feature/issue 209 upstream host based routing (#216)
* from messing around at lunch...initial hacking seems to sort of work..need to think of all the test scenarios * drunken train hacking * docs for upstreamhost
This commit is contained in:
@ -10,7 +10,7 @@ namespace Ocelot.Configuration.Builder
|
||||
public class ReRouteBuilder
|
||||
{
|
||||
private AuthenticationOptions _authenticationOptions;
|
||||
private string _loadBalancerKey;
|
||||
private string _reRouteKey;
|
||||
private string _downstreamPathTemplate;
|
||||
private string _upstreamTemplate;
|
||||
private UpstreamPathTemplate _upstreamTemplatePattern;
|
||||
@ -36,6 +36,7 @@ namespace Ocelot.Configuration.Builder
|
||||
private List<HeaderFindAndReplace> _upstreamHeaderFindAndReplace;
|
||||
private List<HeaderFindAndReplace> _downstreamHeaderFindAndReplace;
|
||||
private readonly List<DownstreamHostAndPort> _downstreamAddresses;
|
||||
private string _upstreamHost;
|
||||
|
||||
public ReRouteBuilder()
|
||||
{
|
||||
@ -48,6 +49,12 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRouteBuilder WithUpstreamHost(string upstreamAddresses)
|
||||
{
|
||||
_upstreamHost = upstreamAddresses;
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRouteBuilder WithLoadBalancer(string loadBalancer)
|
||||
{
|
||||
_loadBalancer = loadBalancer;
|
||||
@ -150,9 +157,9 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
public ReRouteBuilder WithReRouteKey(string loadBalancerKey)
|
||||
public ReRouteBuilder WithReRouteKey(string reRouteKey)
|
||||
{
|
||||
_loadBalancerKey = loadBalancerKey;
|
||||
_reRouteKey = reRouteKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
@ -204,6 +211,7 @@ namespace Ocelot.Configuration.Builder
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public ReRoute Build()
|
||||
{
|
||||
return new ReRoute(
|
||||
@ -223,7 +231,7 @@ namespace Ocelot.Configuration.Builder
|
||||
_fileCacheOptions,
|
||||
_downstreamScheme,
|
||||
_loadBalancer,
|
||||
_loadBalancerKey,
|
||||
_reRouteKey,
|
||||
_useQos,
|
||||
_qosOptions,
|
||||
_enableRateLimiting,
|
||||
@ -233,7 +241,8 @@ namespace Ocelot.Configuration.Builder
|
||||
_serviceName,
|
||||
_upstreamHeaderFindAndReplace,
|
||||
_downstreamHeaderFindAndReplace,
|
||||
_downstreamAddresses);
|
||||
_downstreamAddresses,
|
||||
_upstreamHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +166,7 @@ namespace Ocelot.Configuration.Creator
|
||||
.WithUseServiceDiscovery(fileReRoute.UseServiceDiscovery)
|
||||
.WithUpstreamHeaderFindAndReplace(hAndRs.Upstream)
|
||||
.WithDownstreamHeaderFindAndReplace(hAndRs.Downstream)
|
||||
.WithUpstreamHost(fileReRoute.UpstreamHost)
|
||||
.Build();
|
||||
|
||||
return reRoute;
|
||||
|
@ -42,5 +42,6 @@ namespace Ocelot.Configuration.File
|
||||
public FileHttpHandlerOptions HttpHandlerOptions { get; set; }
|
||||
public bool UseServiceDiscovery {get;set;}
|
||||
public List<FileHostAndPort> DownstreamHostAndPorts {get;set;}
|
||||
public string UpstreamHost { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -33,15 +33,17 @@ namespace Ocelot.Configuration
|
||||
string serviceName,
|
||||
List<HeaderFindAndReplace> upstreamHeadersFindAndReplace,
|
||||
List<HeaderFindAndReplace> downstreamHeadersFindAndReplace,
|
||||
List<DownstreamHostAndPort> downstreamAddresses)
|
||||
List<DownstreamHostAndPort> downstreamAddresses,
|
||||
string upstreamHost)
|
||||
{
|
||||
DownstreamHeadersFindAndReplace = downstreamHeadersFindAndReplace;
|
||||
UpstreamHeadersFindAndReplace = upstreamHeadersFindAndReplace;
|
||||
UpstreamHost = upstreamHost;
|
||||
DownstreamHeadersFindAndReplace = downstreamHeadersFindAndReplace ?? new List<HeaderFindAndReplace>();
|
||||
UpstreamHeadersFindAndReplace = upstreamHeadersFindAndReplace ?? new List<HeaderFindAndReplace>();
|
||||
ServiceName = serviceName;
|
||||
UseServiceDiscovery = useServiceDiscovery;
|
||||
ReRouteKey = reRouteKey;
|
||||
LoadBalancer = loadBalancer;
|
||||
DownstreamAddresses = downstreamAddresses;
|
||||
DownstreamAddresses = downstreamAddresses ?? new List<DownstreamHostAndPort>();
|
||||
DownstreamPathTemplate = downstreamPathTemplate;
|
||||
UpstreamPathTemplate = upstreamPathTemplate;
|
||||
UpstreamHttpMethod = upstreamHttpMethod;
|
||||
@ -53,12 +55,9 @@ namespace Ocelot.Configuration
|
||||
RequestIdKey = requestIdKey;
|
||||
IsCached = isCached;
|
||||
CacheOptions = cacheOptions;
|
||||
ClaimsToQueries = claimsToQueries
|
||||
?? new List<ClaimToThing>();
|
||||
ClaimsToClaims = claimsToClaims
|
||||
?? new List<ClaimToThing>();
|
||||
ClaimsToHeaders = claimsToHeaders
|
||||
?? new List<ClaimToThing>();
|
||||
ClaimsToQueries = claimsToQueries ?? new List<ClaimToThing>();
|
||||
ClaimsToClaims = claimsToClaims ?? new List<ClaimToThing>();
|
||||
ClaimsToHeaders = claimsToHeaders ?? new List<ClaimToThing>();
|
||||
DownstreamScheme = downstreamScheme;
|
||||
IsQos = isQos;
|
||||
QosOptionsOptions = qosOptions;
|
||||
@ -94,6 +93,6 @@ namespace Ocelot.Configuration
|
||||
public List<HeaderFindAndReplace> UpstreamHeadersFindAndReplace {get;private set;}
|
||||
public List<HeaderFindAndReplace> DownstreamHeadersFindAndReplace {get;private set;}
|
||||
public List<DownstreamHostAndPort> DownstreamAddresses {get;private set;}
|
||||
|
||||
public string UpstreamHost { get; private set; }
|
||||
}
|
||||
}
|
||||
|
@ -39,7 +39,8 @@ namespace Ocelot.Configuration.Validator
|
||||
|
||||
private static bool IsNotDuplicateIn(FileReRoute reRoute, List<FileReRoute> reRoutes)
|
||||
{
|
||||
var matchingReRoutes = reRoutes.Where(r => r.UpstreamPathTemplate == reRoute.UpstreamPathTemplate).ToList();
|
||||
var matchingReRoutes = reRoutes
|
||||
.Where(r => r.UpstreamPathTemplate == reRoute.UpstreamPathTemplate && (r.UpstreamHost != reRoute.UpstreamHost || reRoute.UpstreamHost == null)).ToList();
|
||||
|
||||
if(matchingReRoutes.Count == 1)
|
||||
{
|
||||
|
@ -13,44 +13,56 @@ namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
public class DownstreamRouteFinder : IDownstreamRouteFinder
|
||||
{
|
||||
private readonly IUrlPathToUrlTemplateMatcher _urlMatcher;
|
||||
private readonly IPlaceholderNameAndValueFinder __placeholderNameAndValueFinder;
|
||||
private readonly IPlaceholderNameAndValueFinder _placeholderNameAndValueFinder;
|
||||
|
||||
public DownstreamRouteFinder(IUrlPathToUrlTemplateMatcher urlMatcher, IPlaceholderNameAndValueFinder urlPathPlaceholderNameAndValueFinder)
|
||||
{
|
||||
_urlMatcher = urlMatcher;
|
||||
__placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
||||
_placeholderNameAndValueFinder = urlPathPlaceholderNameAndValueFinder;
|
||||
}
|
||||
|
||||
public Response<DownstreamRoute> FindDownstreamRoute(string path, string httpMethod, IOcelotConfiguration configuration)
|
||||
public Response<DownstreamRoute> FindDownstreamRoute(string path, string httpMethod, IOcelotConfiguration configuration, string upstreamHost)
|
||||
{
|
||||
var applicableReRoutes = configuration.ReRoutes.Where(r => r.UpstreamHttpMethod.Count == 0 || r.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower())).OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
|
||||
var downstreamRoutes = new List<DownstreamRoute>();
|
||||
|
||||
var applicableReRoutes = configuration.ReRoutes
|
||||
.Where(r => RouteIsApplicableToThisRequest(r, httpMethod, upstreamHost))
|
||||
.OrderByDescending(x => x.UpstreamTemplatePattern.Priority);
|
||||
|
||||
foreach (var reRoute in applicableReRoutes)
|
||||
{
|
||||
if (path == reRoute.UpstreamTemplatePattern.Template)
|
||||
{
|
||||
return GetPlaceholderNamesAndValues(path, reRoute);
|
||||
}
|
||||
|
||||
var urlMatch = _urlMatcher.Match(path, reRoute.UpstreamTemplatePattern.Template);
|
||||
|
||||
if (urlMatch.Data.Match)
|
||||
{
|
||||
return GetPlaceholderNamesAndValues(path, reRoute);
|
||||
downstreamRoutes.Add(GetPlaceholderNamesAndValues(path, reRoute));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (downstreamRoutes.Any())
|
||||
{
|
||||
var notNullOption = downstreamRoutes.FirstOrDefault(x => !string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
||||
var nullOption = downstreamRoutes.FirstOrDefault(x => string.IsNullOrEmpty(x.ReRoute.UpstreamHost));
|
||||
|
||||
return notNullOption != null ? new OkResponse<DownstreamRoute>(notNullOption) : new OkResponse<DownstreamRoute>(nullOption);
|
||||
}
|
||||
|
||||
return new ErrorResponse<DownstreamRoute>(new List<Error>
|
||||
{
|
||||
new UnableToFindDownstreamRouteError()
|
||||
});
|
||||
}
|
||||
|
||||
private OkResponse<DownstreamRoute> GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
|
||||
private bool RouteIsApplicableToThisRequest(ReRoute reRoute, string httpMethod, string upstreamHost)
|
||||
{
|
||||
var templatePlaceholderNameAndValues = __placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
|
||||
return reRoute.UpstreamHttpMethod.Count == 0 || reRoute.UpstreamHttpMethod.Select(x => x.Method.ToLower()).Contains(httpMethod.ToLower()) && !(!string.IsNullOrEmpty(reRoute.UpstreamHost) && reRoute.UpstreamHost != upstreamHost);
|
||||
}
|
||||
|
||||
return new OkResponse<DownstreamRoute>(new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute));
|
||||
private DownstreamRoute GetPlaceholderNamesAndValues(string path, ReRoute reRoute)
|
||||
{
|
||||
var templatePlaceholderNameAndValues = _placeholderNameAndValueFinder.Find(path, reRoute.UpstreamPathTemplate.Value);
|
||||
|
||||
return new DownstreamRoute(templatePlaceholderNameAndValues.Data, reRoute);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,6 +6,6 @@ namespace Ocelot.DownstreamRouteFinder.Finder
|
||||
{
|
||||
public interface IDownstreamRouteFinder
|
||||
{
|
||||
Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration);
|
||||
Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath, string upstreamHttpMethod, IOcelotConfiguration configuration, string upstreamHost);
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,8 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
{
|
||||
var upstreamUrlPath = context.Request.Path.ToString();
|
||||
|
||||
var upstreamHost = context.Request.Headers["Host"];
|
||||
|
||||
var configuration = await _configProvider.Get();
|
||||
|
||||
if(configuration.IsError)
|
||||
@ -49,7 +51,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
|
||||
_logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath);
|
||||
|
||||
var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method, configuration.Data);
|
||||
var downstreamRoute = _downstreamRouteFinder.FindDownstreamRoute(upstreamUrlPath, context.Request.Method, configuration.Data, upstreamHost);
|
||||
|
||||
if (downstreamRoute.IsError)
|
||||
{
|
||||
@ -66,4 +68,4 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
await _next.Invoke(context);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user