refactor: HttpClientCache and remove not used code current

This commit is contained in:
geffzhang 2017-03-07 08:29:03 +08:00
parent 10db534008
commit 23ad6ed264
7 changed files with 48 additions and 91 deletions

View File

@ -1,6 +1,6 @@
 {  {
"projects": [ "src", "test" ], "projects": [ "src", "test" ],
"sdk": { "sdk": {
"version": "1.0.0-preview2-003133" "version": "1.0.0-preview2-003131"
} }
} }

View File

@ -135,7 +135,7 @@ namespace Ocelot.DependencyInjection
services.AddSingleton<IAuthenticationHandlerFactory, AuthenticationHandlerFactory>(); services.AddSingleton<IAuthenticationHandlerFactory, AuthenticationHandlerFactory>();
services.AddSingleton<IAuthenticationHandlerCreator, AuthenticationHandlerCreator>(); services.AddSingleton<IAuthenticationHandlerCreator, AuthenticationHandlerCreator>();
services.AddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>(); services.AddSingleton<IRateLimitCounterHandler, MemoryCacheRateLimitCounterHandler>();
services.AddSingleton<IHttpClientMessageCacheHandler, MemoryHttpClientMessageCacheHandler>(); services.AddSingleton<IHttpClientCache, MemoryHttpClientCache>();
// see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc // see this for why we register this as singleton http://stackoverflow.com/questions/37371264/invalidoperationexception-unable-to-resolve-service-for-type-microsoft-aspnetc
// could maybe use a scoped data repository // could maybe use a scoped data repository

View File

@ -11,61 +11,23 @@ namespace Ocelot.Requester
{ {
internal class HttpClientBuilder : IHttpClientBuilder internal class HttpClientBuilder : IHttpClientBuilder
{ {
private TimeSpan? _timeout; private readonly Dictionary<int, Func<DelegatingHandler>> _handlers = new Dictionary<int, Func<DelegatingHandler>>();
private readonly List<DelegatingHandler> _handlers = new List<DelegatingHandler>();
private Dictionary<string, string> _defaultHeaders; private Dictionary<string, string> _defaultHeaders;
private CookieContainer _cookieContainer;
private IQoSProvider _qoSProvider;
public IHttpClientBuilder WithCookieContainer(CookieContainer cookieContainer) public IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger)
{ {
_cookieContainer = cookieContainer; _handlers.Add(5000, () => new PollyCircuitBreakingDelegatingHandler(qosProvider, logger));
return this; return this;
}
public IHttpClientBuilder WithTimeout(TimeSpan timeout)
{
_timeout = timeout;
return this;
}
public IHttpClientBuilder WithHandler(DelegatingHandler handler)
{
_handlers.Add(handler);
return this;
}
public IHttpClientBuilder WithDefaultRequestHeaders(Dictionary<string, string> headers)
{
_defaultHeaders = headers;
return this;
} }
public IHttpClient Create() public IHttpClient Create()
{ {
HttpClientHandler httpclientHandler = null; var httpclientHandler = new HttpClientHandler();
if (_cookieContainer != null)
{
httpclientHandler = new HttpClientHandler() { CookieContainer = _cookieContainer };
}
else
{
httpclientHandler = new HttpClientHandler();
}
if (httpclientHandler.SupportsAutomaticDecompression)
{
httpclientHandler.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;
}
var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler)); var client = new HttpClient(CreateHttpMessageHandler(httpclientHandler));
if (_timeout.HasValue)
{
client.Timeout = _timeout.Value;
}
if (_defaultHeaders == null) if (_defaultHeaders == null)
{ {
return new HttpClientWrapper(client); return new HttpClientWrapper(client);
@ -81,11 +43,18 @@ namespace Ocelot.Requester
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler) private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
{ {
foreach (var handler in _handlers)
{ _handlers
handler.InnerHandler = httpMessageHandler; .OrderByDescending(handler => handler.Key)
httpMessageHandler = handler; .Select(handler => handler.Value)
} .Reverse()
.ToList()
.ForEach(handler =>
{
var delegatingHandler = handler();
delegatingHandler.InnerHandler = httpMessageHandler;
httpMessageHandler = delegatingHandler;
});
return httpMessageHandler; return httpMessageHandler;
} }
} }

View File

@ -11,10 +11,10 @@ namespace Ocelot.Requester
{ {
public class HttpClientHttpRequester : IHttpRequester public class HttpClientHttpRequester : IHttpRequester
{ {
private IHttpClientMessageCacheHandler _cacheHandlers; private readonly IHttpClientCache _cacheHandlers;
private readonly IOcelotLogger _logger; private readonly IOcelotLogger _logger;
public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientMessageCacheHandler cacheHandlers) public HttpClientHttpRequester(IOcelotLoggerFactory loggerFactory, IHttpClientCache cacheHandlers)
{ {
_logger = loggerFactory.CreateLogger<HttpClientHttpRequester>(); _logger = loggerFactory.CreateLogger<HttpClientHttpRequester>();
_cacheHandlers = cacheHandlers; _cacheHandlers = cacheHandlers;
@ -24,21 +24,13 @@ namespace Ocelot.Requester
{ {
var builder = new HttpClientBuilder(); var builder = new HttpClientBuilder();
builder.WithCookieContainer(request.CookieContainer); var cacheKey = GetCacheKey(request, builder);
string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}"; var httpClient = _cacheHandlers.Get(cacheKey);
if (request.IsQos)
{
builder.WithHandler(new PollyCircuitBreakingDelegatingHandler(request.QosProvider, _logger));
baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}";
}
IHttpClient httpClient = _cacheHandlers.Get(baseUrl);
if (httpClient == null) if (httpClient == null)
{ {
httpClient = builder.Create(); httpClient = builder.Create();
_cacheHandlers.Set(baseUrl, httpClient, TimeSpan.FromMinutes(30)); _cacheHandlers.Set(cacheKey, httpClient, TimeSpan.FromHours(6));
} }
try try
@ -62,5 +54,18 @@ namespace Ocelot.Requester
} }
} }
private string GetCacheKey(Request.Request request, HttpClientBuilder builder)
{
string baseUrl = $"{request.HttpRequestMessage.RequestUri.Scheme}://{request.HttpRequestMessage.RequestUri.Authority}";
if (request.IsQos)
{
builder.WithQos(request.QosProvider, _logger);
baseUrl = $"{baseUrl}{request.QosProvider.CircuitBreaker.CircuitBreakerPolicy.PolicyKey}";
}
return baseUrl;
}
} }
} }

View File

@ -11,28 +11,11 @@ namespace Ocelot.Requester
{ {
public interface IHttpClientBuilder public interface IHttpClientBuilder
{ {
/// <summary>
/// Sets the cookie container used to store server cookies by the handler
/// </summary>
/// <param name="cookieContainer"></param>
/// <returns></returns>
IHttpClientBuilder WithCookieContainer(CookieContainer cookieContainer);
/// <summary> /// <summary>
/// Sets the number of milliseconds to wait before the request times out. /// Sets a PollyCircuitBreakingDelegatingHandler .
/// </summary> /// </summary>
IHttpClientBuilder WithTimeout(TimeSpan timeout); IHttpClientBuilder WithQos(IQoSProvider qosProvider, IOcelotLogger logger);
/// <summary>
/// Sets a DelegatingHandler.
/// Can be reused to set several different Handlers in a pipeline.
/// </summary>
IHttpClientBuilder WithHandler(DelegatingHandler handler);
/// <summary>
/// Sets Default HttpRequestHeaders
/// </summary>
IHttpClientBuilder WithDefaultRequestHeaders(Dictionary<string, string> headers);
/// <summary> /// <summary>
/// Creates the <see cref="HttpClient"/> /// Creates the <see cref="HttpClient"/>

View File

@ -6,7 +6,7 @@ using System.Threading.Tasks;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
public interface IHttpClientMessageCacheHandler public interface IHttpClientCache
{ {
bool Exists(string id); bool Exists(string id);
IHttpClient Get(string id); IHttpClient Get(string id);

View File

@ -7,18 +7,18 @@ using System.Threading.Tasks;
namespace Ocelot.Requester namespace Ocelot.Requester
{ {
public class MemoryHttpClientMessageCacheHandler : IHttpClientMessageCacheHandler public class MemoryHttpClientCache : IHttpClientCache
{ {
private readonly IMemoryCache _memoryCache; private readonly IMemoryCache _memoryCache;
public MemoryHttpClientMessageCacheHandler(IMemoryCache memoryCache) public MemoryHttpClientCache(IMemoryCache memoryCache)
{ {
_memoryCache = memoryCache; _memoryCache = memoryCache;
} }
public void Set(string id, IHttpClient counter, TimeSpan expirationTime) public void Set(string id, IHttpClient client, TimeSpan expirationTime)
{ {
_memoryCache.Set(id, counter, new MemoryCacheEntryOptions().SetAbsoluteExpiration(expirationTime)); _memoryCache.Set(id, client, new MemoryCacheEntryOptions().SetAbsoluteExpiration(expirationTime));
} }
public bool Exists(string id) public bool Exists(string id)