mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-04 09:15:27 +08:00 
			
		
		
		
	merged develop
This commit is contained in:
		
							
								
								
									
										
											BIN
										
									
								
								src/.DS_Store
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/.DS_Store
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/Ocelot/.DS_Store
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/Ocelot/.DS_Store
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										
											BIN
										
									
								
								src/Ocelot/Authentication/Handler/.DS_Store
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										
											BIN
										
									
								
								src/Ocelot/Authentication/Handler/.DS_Store
									
									
									
									
										vendored
									
									
								
							
										
											Binary file not shown.
										
									
								
							@@ -28,6 +28,8 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
        private int _downstreamPort;
 | 
			
		||||
        private string _loadBalancer;
 | 
			
		||||
        private ServiceProviderConfiguraion _serviceProviderConfiguraion;
 | 
			
		||||
        private bool _useQos;
 | 
			
		||||
        private QoSOptions _qosOptions;
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithLoadBalancer(string loadBalancer)
 | 
			
		||||
        {
 | 
			
		||||
@@ -135,6 +137,19 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithIsQos(bool input)
 | 
			
		||||
        {
 | 
			
		||||
            _useQos = input;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithQosOptions(QoSOptions input)
 | 
			
		||||
        {
 | 
			
		||||
            _qosOptions = input;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
       
 | 
			
		||||
 | 
			
		||||
        public ReRouteBuilder WithLoadBalancerKey(string loadBalancerKey)
 | 
			
		||||
        {
 | 
			
		||||
            _loadBalancerKey = loadBalancerKey;
 | 
			
		||||
@@ -175,7 +190,9 @@ namespace Ocelot.Configuration.Builder
 | 
			
		||||
                _downstreamHost, 
 | 
			
		||||
                _downstreamPort, 
 | 
			
		||||
                _loadBalancerKey, 
 | 
			
		||||
                _serviceProviderConfiguraion);
 | 
			
		||||
                _serviceProviderConfiguraion, 
 | 
			
		||||
                _useQos, 
 | 
			
		||||
                _qosOptions);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -95,12 +95,14 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
            var loadBalancerKey = BuildLoadBalancerKey(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var upstreamTemplatePattern = BuildUpstreamTemplate(fileReRoute);
 | 
			
		||||
            var isQos = fileReRoute.QoSOptions.ExceptionsAllowedBeforeBreaking > 0 && fileReRoute.QoSOptions.TimeoutValue >0;
 | 
			
		||||
 | 
			
		||||
            var serviceProviderConfiguration = BuildServiceProviderConfiguration(fileReRoute, globalConfiguration);
 | 
			
		||||
 | 
			
		||||
            var authOptionsForRoute = BuildAuthenticationOptions(fileReRoute);
 | 
			
		||||
 | 
			
		||||
            var claimsToHeaders = BuildAddThingsToRequest(fileReRoute.AddHeadersToRequest);
 | 
			
		||||
 
 | 
			
		||||
 | 
			
		||||
            var claimsToClaims = BuildAddThingsToRequest(fileReRoute.AddClaimsToRequest);
 | 
			
		||||
 | 
			
		||||
@@ -137,7 +139,7 @@ namespace Ocelot.Configuration.Creator
 | 
			
		||||
        {
 | 
			
		||||
            return !string.IsNullOrEmpty(fileReRoute.AuthenticationOptions?.Provider);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
      
 | 
			
		||||
        private bool IsAuthorised(FileReRoute fileReRoute)
 | 
			
		||||
        {
 | 
			
		||||
            return fileReRoute.RouteClaimsRequirement?.Count > 0;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										16
									
								
								src/Ocelot/Configuration/File/FileQoSOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/Ocelot/Configuration/File/FileQoSOptions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration.File
 | 
			
		||||
{
 | 
			
		||||
    public class FileQoSOptions
 | 
			
		||||
    {
 | 
			
		||||
        public int ExceptionsAllowedBeforeBreaking { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int DurationOfBreak { get; set; }
 | 
			
		||||
 | 
			
		||||
        public int TimeoutValue { get; set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -12,6 +12,7 @@ namespace Ocelot.Configuration.File
 | 
			
		||||
            AddQueriesToRequest = new Dictionary<string, string>();
 | 
			
		||||
            AuthenticationOptions = new FileAuthenticationOptions();
 | 
			
		||||
            FileCacheOptions = new FileCacheOptions();
 | 
			
		||||
            QoSOptions = new FileQoSOptions();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string DownstreamPathTemplate { get; set; }
 | 
			
		||||
@@ -29,6 +30,7 @@ namespace Ocelot.Configuration.File
 | 
			
		||||
        public string DownstreamScheme {get;set;}
 | 
			
		||||
        public string DownstreamHost {get;set;}
 | 
			
		||||
        public int DownstreamPort { get; set; }
 | 
			
		||||
        public FileQoSOptions QoSOptions { get; set; }
 | 
			
		||||
        public string LoadBalancer {get;set;}
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										29
									
								
								src/Ocelot/Configuration/QoSOptions.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								src/Ocelot/Configuration/QoSOptions.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,29 @@
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Configuration
 | 
			
		||||
{
 | 
			
		||||
    public class QoSOptions
 | 
			
		||||
    {
 | 
			
		||||
        public QoSOptions(int exceptionsAllowedBeforeBreaking, int durationofBreak, int timeoutValue, TimeoutStrategy timeoutStrategy = TimeoutStrategy.Pessimistic)
 | 
			
		||||
        {
 | 
			
		||||
            ExceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
			
		||||
            DurationOfBreak = TimeSpan.FromMilliseconds(durationofBreak);
 | 
			
		||||
            TimeoutValue = TimeSpan.FromMilliseconds(timeoutValue);
 | 
			
		||||
            TimeoutStrategy = timeoutStrategy;
 | 
			
		||||
        }
 | 
			
		||||
         
 | 
			
		||||
 | 
			
		||||
        public int ExceptionsAllowedBeforeBreaking { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public TimeSpan DurationOfBreak { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public TimeSpan TimeoutValue { get; private set; }
 | 
			
		||||
 | 
			
		||||
        public TimeoutStrategy TimeoutStrategy { get; private set; }
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -8,16 +8,27 @@ namespace Ocelot.Configuration
 | 
			
		||||
    public class ReRoute
 | 
			
		||||
    {
 | 
			
		||||
        public ReRoute(PathTemplate downstreamPathTemplate, 
 | 
			
		||||
            PathTemplate upstreamTemplate, HttpMethod upstreamHttpMethod, 
 | 
			
		||||
            PathTemplate upstreamTemplate, 
 | 
			
		||||
            HttpMethod upstreamHttpMethod, 
 | 
			
		||||
            string upstreamTemplatePattern, 
 | 
			
		||||
            bool isAuthenticated, AuthenticationOptions authenticationOptions, 
 | 
			
		||||
            bool isAuthenticated, 
 | 
			
		||||
            AuthenticationOptions authenticationOptions, 
 | 
			
		||||
            List<ClaimToThing> configurationHeaderExtractorProperties, 
 | 
			
		||||
            List<ClaimToThing> claimsToClaims, 
 | 
			
		||||
            Dictionary<string, string> routeClaimsRequirement, bool isAuthorised, 
 | 
			
		||||
            Dictionary<string, string> routeClaimsRequirement, 
 | 
			
		||||
            bool isAuthorised, 
 | 
			
		||||
            List<ClaimToThing> claimsToQueries, 
 | 
			
		||||
            string requestIdKey, bool isCached, CacheOptions fileCacheOptions, 
 | 
			
		||||
            string downstreamScheme, string loadBalancer, string downstreamHost, 
 | 
			
		||||
            int downstreamPort, string loadBalancerKey, ServiceProviderConfiguraion serviceProviderConfiguraion)
 | 
			
		||||
            string requestIdKey, 
 | 
			
		||||
            bool isCached, 
 | 
			
		||||
            CacheOptions fileCacheOptions, 
 | 
			
		||||
            string downstreamScheme, 
 | 
			
		||||
            string loadBalancer, 
 | 
			
		||||
            string downstreamHost, 
 | 
			
		||||
            int downstreamPort, 
 | 
			
		||||
            string loadBalancerKey, 
 | 
			
		||||
            ServiceProviderConfiguraion serviceProviderConfiguraion,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos)
 | 
			
		||||
        {
 | 
			
		||||
            LoadBalancerKey = loadBalancerKey;
 | 
			
		||||
            ServiceProviderConfiguraion = serviceProviderConfiguraion;
 | 
			
		||||
@@ -42,6 +53,8 @@ namespace Ocelot.Configuration
 | 
			
		||||
            ClaimsToHeaders = configurationHeaderExtractorProperties 
 | 
			
		||||
                ?? new List<ClaimToThing>();
 | 
			
		||||
                DownstreamScheme = downstreamScheme;
 | 
			
		||||
            IsQos = isQos;
 | 
			
		||||
            QosOptions = qos;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public string LoadBalancerKey {get;private set;}
 | 
			
		||||
@@ -60,6 +73,8 @@ namespace Ocelot.Configuration
 | 
			
		||||
        public bool IsCached { get; private set; }
 | 
			
		||||
        public CacheOptions FileCacheOptions { get; private set; }
 | 
			
		||||
        public string DownstreamScheme {get;private set;}
 | 
			
		||||
        public bool IsQos { get; private set; }
 | 
			
		||||
        public QoSOptions QosOptions { get; private set; }
 | 
			
		||||
        public string LoadBalancer {get;private set;}
 | 
			
		||||
        public string DownstreamHost { get; private set; }
 | 
			
		||||
        public int DownstreamPort { get; private set; }
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Builder
 | 
			
		||||
{
 | 
			
		||||
@@ -15,7 +16,9 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            IRequestCookieCollection cookies, 
 | 
			
		||||
            QueryString queryString, 
 | 
			
		||||
            string contentType, 
 | 
			
		||||
            RequestId.RequestId requestId)
 | 
			
		||||
            RequestId.RequestId requestId,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos)
 | 
			
		||||
        {
 | 
			
		||||
            var request = await new RequestBuilder()
 | 
			
		||||
                .WithHttpMethod(httpMethod)
 | 
			
		||||
@@ -26,6 +29,8 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
                .WithHeaders(headers)
 | 
			
		||||
                .WithRequestId(requestId)
 | 
			
		||||
                .WithCookies(cookies)
 | 
			
		||||
                .WithIsQos(isQos)
 | 
			
		||||
                .WithQos(qos)
 | 
			
		||||
                .Build();
 | 
			
		||||
 | 
			
		||||
            return new OkResponse<Request>(request);
 | 
			
		||||
 
 | 
			
		||||
@@ -2,6 +2,7 @@
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Builder
 | 
			
		||||
{
 | 
			
		||||
@@ -13,7 +14,9 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            IHeaderDictionary headers,
 | 
			
		||||
            IRequestCookieCollection cookies,
 | 
			
		||||
            QueryString queryString,
 | 
			
		||||
            string contentType, 
 | 
			
		||||
            RequestId.RequestId requestId);
 | 
			
		||||
            string contentType,
 | 
			
		||||
            RequestId.RequestId requestId,
 | 
			
		||||
            bool isQos,
 | 
			
		||||
            QoSOptions qos);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -8,6 +8,7 @@ using System.Net.Http.Headers;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Microsoft.AspNetCore.Http;
 | 
			
		||||
using Microsoft.Extensions.Primitives;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request.Builder
 | 
			
		||||
{
 | 
			
		||||
@@ -22,6 +23,8 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
        private RequestId.RequestId _requestId;
 | 
			
		||||
        private IRequestCookieCollection _cookies;
 | 
			
		||||
        private readonly string[] _unsupportedHeaders = {"host"};
 | 
			
		||||
        private bool _isQos;
 | 
			
		||||
        private QoSOptions _qos;
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithHttpMethod(string httpMethod)
 | 
			
		||||
        {
 | 
			
		||||
@@ -71,6 +74,18 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithIsQos(bool isqos)
 | 
			
		||||
        {
 | 
			
		||||
            _isQos = isqos;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public RequestBuilder WithQos(QoSOptions qos)
 | 
			
		||||
        {
 | 
			
		||||
            _qos = qos;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Request> Build()
 | 
			
		||||
        {
 | 
			
		||||
            var uri = CreateUri();
 | 
			
		||||
@@ -90,7 +105,7 @@ namespace Ocelot.Request.Builder
 | 
			
		||||
 | 
			
		||||
            var cookieContainer = CreateCookieContainer(uri);
 | 
			
		||||
 | 
			
		||||
            return new Request(httpRequestMessage, cookieContainer);
 | 
			
		||||
            return new Request(httpRequestMessage, cookieContainer,_isQos,_qos);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private Uri CreateUri()
 | 
			
		||||
 
 | 
			
		||||
@@ -32,7 +32,8 @@ namespace Ocelot.Request.Middleware
 | 
			
		||||
            var buildResult = await _requestCreator
 | 
			
		||||
                .Build(context.Request.Method, DownstreamUrl, context.Request.Body,
 | 
			
		||||
                    context.Request.Headers, context.Request.Cookies, context.Request.QueryString,
 | 
			
		||||
                    context.Request.ContentType, new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier));
 | 
			
		||||
                    context.Request.ContentType, new RequestId.RequestId(DownstreamRoute?.ReRoute?.RequestIdKey, context.TraceIdentifier),
 | 
			
		||||
                    DownstreamRoute.ReRoute.IsQos,DownstreamRoute.ReRoute.QosOptions);
 | 
			
		||||
 | 
			
		||||
            if (buildResult.IsError)
 | 
			
		||||
            {
 | 
			
		||||
 
 | 
			
		||||
@@ -1,17 +1,23 @@
 | 
			
		||||
using System.Net;
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Request
 | 
			
		||||
{
 | 
			
		||||
    public class Request
 | 
			
		||||
    {
 | 
			
		||||
        public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer)
 | 
			
		||||
        public Request(HttpRequestMessage httpRequestMessage, CookieContainer cookieContainer,bool isQos, QoSOptions qos)
 | 
			
		||||
        {
 | 
			
		||||
            HttpRequestMessage = httpRequestMessage;
 | 
			
		||||
            CookieContainer = cookieContainer;
 | 
			
		||||
            IsQos = isQos;
 | 
			
		||||
            Qos = qos;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public HttpRequestMessage HttpRequestMessage { get; private set; }
 | 
			
		||||
        public CookieContainer CookieContainer { get; private set; }
 | 
			
		||||
        public bool IsQos { get; private set; }
 | 
			
		||||
        public QoSOptions Qos { get; private set; }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										74
									
								
								src/Ocelot/Requester/CircuitBreakingDelegatingHandler.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								src/Ocelot/Requester/CircuitBreakingDelegatingHandler.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Polly;
 | 
			
		||||
using Polly.CircuitBreaker;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Net;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class CircuitBreakingDelegatingHandler : DelegatingHandler
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
        private readonly int _exceptionsAllowedBeforeBreaking;
 | 
			
		||||
        private readonly TimeSpan _durationOfBreak;
 | 
			
		||||
        private readonly Policy _circuitBreakerPolicy;
 | 
			
		||||
        private readonly TimeoutPolicy _timeoutPolicy;
 | 
			
		||||
 | 
			
		||||
        public CircuitBreakingDelegatingHandler(int exceptionsAllowedBeforeBreaking, TimeSpan durationOfBreak,TimeSpan timeoutValue
 | 
			
		||||
            ,TimeoutStrategy timeoutStrategy, IOcelotLogger logger, HttpMessageHandler innerHandler)
 | 
			
		||||
            : base(innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            this._exceptionsAllowedBeforeBreaking = exceptionsAllowedBeforeBreaking;
 | 
			
		||||
            this._durationOfBreak = durationOfBreak;
 | 
			
		||||
 | 
			
		||||
            _circuitBreakerPolicy = Policy
 | 
			
		||||
                .Handle<HttpRequestException>()
 | 
			
		||||
                .Or<TimeoutRejectedException>()
 | 
			
		||||
                .Or<TimeoutException>()
 | 
			
		||||
                .CircuitBreakerAsync(
 | 
			
		||||
                    exceptionsAllowedBeforeBreaking: exceptionsAllowedBeforeBreaking,
 | 
			
		||||
                    durationOfBreak: durationOfBreak,
 | 
			
		||||
                    onBreak: (ex, breakDelay) =>
 | 
			
		||||
                    {
 | 
			
		||||
                        _logger.LogError(".Breaker logging: Breaking the circuit for " + breakDelay.TotalMilliseconds + "ms!", ex);
 | 
			
		||||
                    },
 | 
			
		||||
                    onReset: () => _logger.LogDebug(".Breaker logging: Call ok! Closed the circuit again."),
 | 
			
		||||
                    onHalfOpen: () => _logger.LogDebug(".Breaker logging: Half-open; next call is a trial.")
 | 
			
		||||
                    );
 | 
			
		||||
            _timeoutPolicy = Policy.TimeoutAsync(timeoutValue, timeoutStrategy);
 | 
			
		||||
            _logger = logger;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
 | 
			
		||||
        {
 | 
			
		||||
            Task<HttpResponseMessage> responseTask = null;
 | 
			
		||||
 | 
			
		||||
            try
 | 
			
		||||
            {
 | 
			
		||||
                responseTask = Policy.WrapAsync(_circuitBreakerPolicy, _timeoutPolicy).ExecuteAsync<HttpResponseMessage>(() =>
 | 
			
		||||
                {
 | 
			
		||||
                    return  base.SendAsync(request,cancellationToken);
 | 
			
		||||
                });
 | 
			
		||||
                return responseTask;
 | 
			
		||||
            }
 | 
			
		||||
            catch (BrokenCircuitException ex)
 | 
			
		||||
            {
 | 
			
		||||
                _logger.LogError($"Reached to allowed number of exceptions. Circuit is open. AllowedExceptionCount: {_exceptionsAllowedBeforeBreaking}, DurationOfBreak: {_durationOfBreak}",ex);
 | 
			
		||||
                throw;
 | 
			
		||||
            }
 | 
			
		||||
            catch (HttpRequestException)
 | 
			
		||||
            {
 | 
			
		||||
                return responseTask;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private static bool IsTransientFailure(HttpResponseMessage result)
 | 
			
		||||
        {
 | 
			
		||||
            return result.StatusCode >= HttpStatusCode.InternalServerError;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										42
									
								
								src/Ocelot/Requester/HttpClientBuilder.cs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								src/Ocelot/Requester/HttpClientBuilder.cs
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,42 @@
 | 
			
		||||
using Ocelot.Configuration;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
using Ocelot.Values;
 | 
			
		||||
using Polly.Timeout;
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections.Generic;
 | 
			
		||||
using System.Linq;
 | 
			
		||||
using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    internal class HttpClientBuilder
 | 
			
		||||
    {
 | 
			
		||||
        private readonly Dictionary<int, Func<DelegatingHandler>> handlers = new Dictionary<int, Func<DelegatingHandler>>();
 | 
			
		||||
 | 
			
		||||
        public HttpClientBuilder WithCircuitBreaker(QoSOptions qos, IOcelotLogger logger, HttpMessageHandler innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            handlers.Add(5000, () => new CircuitBreakingDelegatingHandler(qos.ExceptionsAllowedBeforeBreaking, qos.DurationOfBreak, qos.TimeoutValue, qos.TimeoutStrategy, logger, innerHandler));
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        internal HttpClient Build(HttpMessageHandler innerHandler)
 | 
			
		||||
        {
 | 
			
		||||
            return handlers.Any() ? new HttpClient(CreateHttpMessageHandler()) : new HttpClient(innerHandler);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        private HttpMessageHandler CreateHttpMessageHandler()
 | 
			
		||||
        {
 | 
			
		||||
            HttpMessageHandler httpMessageHandler = new HttpClientHandler();
 | 
			
		||||
 | 
			
		||||
            handlers.OrderByDescending(handler => handler.Key).Select(handler => handler.Value).Reverse().ToList().ForEach(handler =>
 | 
			
		||||
            {
 | 
			
		||||
                var delegatingHandler = handler();
 | 
			
		||||
                delegatingHandler.InnerHandler = httpMessageHandler;
 | 
			
		||||
                httpMessageHandler = delegatingHandler;
 | 
			
		||||
            });
 | 
			
		||||
 | 
			
		||||
            return httpMessageHandler;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -4,28 +4,44 @@ using System.Net.Http;
 | 
			
		||||
using System.Threading.Tasks;
 | 
			
		||||
using Ocelot.Errors;
 | 
			
		||||
using Ocelot.Responses;
 | 
			
		||||
using Ocelot.Logging;
 | 
			
		||||
 | 
			
		||||
namespace Ocelot.Requester
 | 
			
		||||
{
 | 
			
		||||
    public class HttpClientHttpRequester : IHttpRequester
 | 
			
		||||
    {
 | 
			
		||||
        private readonly IOcelotLogger _logger;
 | 
			
		||||
 
 | 
			
		||||
        public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory)
 | 
			
		||||
        {
 | 
			
		||||
            _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public async Task<Response<HttpResponseMessage>> GetResponse(Request.Request request)
 | 
			
		||||
        {
 | 
			
		||||
            HttpClientBuilder builder = new HttpClientBuilder();    
 | 
			
		||||
 | 
			
		||||
            using (var handler = new HttpClientHandler { CookieContainer = request.CookieContainer })
 | 
			
		||||
            using (var httpClient = new HttpClient(handler))
 | 
			
		||||
            {
 | 
			
		||||
                try
 | 
			
		||||
                if (request.IsQos)
 | 
			
		||||
                {
 | 
			
		||||
                    var response = await httpClient.SendAsync(request.HttpRequestMessage);
 | 
			
		||||
                    return new OkResponse<HttpResponseMessage>(response);
 | 
			
		||||
                }
 | 
			
		||||
                catch (Exception exception)
 | 
			
		||||
                    builder.WithCircuitBreaker(request.Qos, _logger, handler);
 | 
			
		||||
                }           
 | 
			
		||||
                using (var httpClient = builder.Build(handler))
 | 
			
		||||
                {
 | 
			
		||||
                    return
 | 
			
		||||
                        new ErrorResponse<HttpResponseMessage>(new List<Error>
 | 
			
		||||
                        {
 | 
			
		||||
                            new UnableToCompleteRequestError(exception)
 | 
			
		||||
                        });
 | 
			
		||||
                    try
 | 
			
		||||
                    {
 | 
			
		||||
                        var response = await httpClient.SendAsync(request.HttpRequestMessage);
 | 
			
		||||
                        return new OkResponse<HttpResponseMessage>(response);
 | 
			
		||||
                    }
 | 
			
		||||
                    catch (Exception exception)
 | 
			
		||||
                    {
 | 
			
		||||
                        return
 | 
			
		||||
                            new ErrorResponse<HttpResponseMessage>(new List<Error>
 | 
			
		||||
                            {
 | 
			
		||||
                                new UnableToCompleteRequestError(exception)
 | 
			
		||||
                            });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -7,5 +7,7 @@ namespace Ocelot.Requester
 | 
			
		||||
    public interface IHttpRequester
 | 
			
		||||
    {
 | 
			
		||||
        Task<Response<HttpResponseMessage>> GetResponse(Request.Request request);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -1,38 +1,38 @@
 | 
			
		||||
{
 | 
			
		||||
  "version": "0.0.0-dev",
 | 
			
		||||
 | 
			
		||||
    "dependencies": {
 | 
			
		||||
        "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Configuration.Json": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Logging": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Logging.Console": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Logging.Debug": "1.1.0",
 | 
			
		||||
        "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Http": "1.1.0",
 | 
			
		||||
        "System.Text.RegularExpressions": "4.3.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.JwtBearer": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.Google": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.Facebook": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.Twitter": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Authentication": "1.1.0",
 | 
			
		||||
        "IdentityServer4.AccessTokenValidation": "1.0.2",
 | 
			
		||||
        "Microsoft.AspNetCore.Mvc": "1.1.0",
 | 
			
		||||
        "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
 | 
			
		||||
        "Microsoft.NETCore.App": "1.1.0",
 | 
			
		||||
        "CacheManager.Core": "0.9.2",
 | 
			
		||||
        "CacheManager.Microsoft.Extensions.Configuration": "0.9.2",
 | 
			
		||||
        "CacheManager.Microsoft.Extensions.Logging": "0.9.2",
 | 
			
		||||
        "Consul": "0.7.2.1"
 | 
			
		||||
    },
 | 
			
		||||
  "dependencies": {
 | 
			
		||||
    "Microsoft.AspNetCore.Server.IISIntegration": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Configuration.FileExtensions": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Configuration.Json": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Logging": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Logging.Console": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Logging.Debug": "1.1.0",
 | 
			
		||||
    "Microsoft.Extensions.Options.ConfigurationExtensions": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Http": "1.1.0",
 | 
			
		||||
    "System.Text.RegularExpressions": "4.3.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.OAuth": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.OpenIdConnect": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.Cookies": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.Google": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.Facebook": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.Twitter": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication.MicrosoftAccount": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Authentication": "1.1.0",
 | 
			
		||||
    "IdentityServer4.AccessTokenValidation": "1.0.2",
 | 
			
		||||
    "Microsoft.AspNetCore.Mvc": "1.1.0",
 | 
			
		||||
    "Microsoft.AspNetCore.Server.Kestrel": "1.1.0",
 | 
			
		||||
    "Microsoft.NETCore.App": "1.1.0",
 | 
			
		||||
    "CacheManager.Core": "0.9.2",
 | 
			
		||||
    "CacheManager.Microsoft.Extensions.Configuration": "0.9.2",
 | 
			
		||||
    "CacheManager.Microsoft.Extensions.Logging": "0.9.2",
 | 
			
		||||
    "Consul": "0.7.2.1",
 | 
			
		||||
    "Polly": "5.0.3"
 | 
			
		||||
  },
 | 
			
		||||
  "runtimes": {
 | 
			
		||||
    "win10-x64": {},
 | 
			
		||||
    "osx.10.11-x64":{},
 | 
			
		||||
    "osx.10.11-x64": {},
 | 
			
		||||
    "win7-x64": {}
 | 
			
		||||
  },
 | 
			
		||||
  "frameworks": {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user