mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-06-19 14:08:15 +08:00
* changed name to cache options to fix issue #146 * Add acceptance test that exposes JSON deserialization bug from issue #146 - Create InMemoryJsonHandle for CacheManager that mimics DictionaryHandle but uses ICacheSerializer to serialize/deserialize values instead of saving references - Add CacheManager.Serialization.Json package - Add StartupWithCustomCacheHandle class that extends Startup and overrides ConfigureServices to register InMemoryJsonHandle - Add GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache method to initiate Ocelot with StartupWithCustomCacheHandle - Add test should_return_response_200_with_simple_url_when_using_jsonserialized_cache * Create Acceptance test that exposes issue #152 - Add GivenOcelotIsRunningUsingJsonSerializedCache() that initializes Ocelot with InMemoryJsonHandle - Add should_return_cached_response_when_using_jsonserialized_cache test * Change Consul port to 9502 on should_return_response_200_with_simple_url_when_using_jsonserialized_cache() test * Implement mapping of HttpResponseMessage to CachedResponse to enable distributed caching - Add CachedResponse class that holds HttpResponse data - Add mapping methods in OutputCacheMiddleware to create HttpResponseMessage from CachedResponse and vice versa - Replace HttpResponseMessage with CachedResponse in services registrations - Replace HttpResponseMessage with CachedResponse in OutputCacheController's IOcelotCache * Fix unit tests for OutputCacheMiddleware and OutputCacheController by replacing HttpResponseMessage with CachedResponse * Add .editorconfig with default identation settings (spaces with size 4) * Re-format broken files with new identation settings * Add Startup_WithConsul_And_CustomCacheHandle class - Use Startup_WithConsul_And_CustomCacheHandle in GivenOcelotIsRunningUsingConsulToStoreConfigAndJsonSerializedCache step * Do minor cleanups - Rename StartupWithCustomCacheHandle to Startup_WithCustomCacheHandle for better readability - Remove cachemanager settings Action in Startup since it is not used anymore * Drop Task in CreateHttpResponseMessage - unnecessary overhead * Make setters private in CachedResponse - Rework CreateCachedResponse to use new CachedResponse constructor
This commit is contained in:

committed by
Tom Pallister

parent
3b27bb376e
commit
48b5a32676
25
src/Ocelot/Cache/CachedResponse.cs
Normal file
25
src/Ocelot/Cache/CachedResponse.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace Ocelot.Cache
|
||||
{
|
||||
public class CachedResponse
|
||||
{
|
||||
public CachedResponse(
|
||||
HttpStatusCode statusCode = HttpStatusCode.OK,
|
||||
Dictionary<string, IEnumerable<string>> headers = null,
|
||||
string body = null
|
||||
)
|
||||
{
|
||||
StatusCode = statusCode;
|
||||
Headers = headers ?? new Dictionary<string, IEnumerable<string>>();
|
||||
Body = body ?? "";
|
||||
}
|
||||
|
||||
public HttpStatusCode StatusCode { get; private set; }
|
||||
|
||||
public Dictionary<string, IEnumerable<string>> Headers { get; private set; }
|
||||
|
||||
public string Body { get; private set; }
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Http;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using System.IO;
|
||||
|
||||
namespace Ocelot.Cache.Middleware
|
||||
{
|
||||
@ -13,15 +14,15 @@ namespace Ocelot.Cache.Middleware
|
||||
{
|
||||
private readonly RequestDelegate _next;
|
||||
private readonly IOcelotLogger _logger;
|
||||
private readonly IOcelotCache<HttpResponseMessage> _outputCache;
|
||||
private readonly IOcelotCache<CachedResponse> _outputCache;
|
||||
private readonly IRegionCreator _regionCreator;
|
||||
|
||||
public OutputCacheMiddleware(RequestDelegate next,
|
||||
IOcelotLoggerFactory loggerFactory,
|
||||
IRequestScopedDataRepository scopedDataRepository,
|
||||
IOcelotCache<HttpResponseMessage> outputCache,
|
||||
IOcelotCache<CachedResponse> outputCache,
|
||||
IRegionCreator regionCreator)
|
||||
:base(scopedDataRepository)
|
||||
: base(scopedDataRepository)
|
||||
{
|
||||
_next = next;
|
||||
_outputCache = outputCache;
|
||||
@ -40,14 +41,15 @@ namespace Ocelot.Cache.Middleware
|
||||
var downstreamUrlKey = $"{DownstreamRequest.Method.Method}-{DownstreamRequest.RequestUri.OriginalString}";
|
||||
|
||||
_logger.LogDebug("started checking cache for {downstreamUrlKey}", downstreamUrlKey);
|
||||
|
||||
|
||||
var cached = _outputCache.Get(downstreamUrlKey, DownstreamRoute.ReRoute.CacheOptions.Region);
|
||||
|
||||
if (cached != null)
|
||||
{
|
||||
_logger.LogDebug("cache entry exists for {downstreamUrlKey}", downstreamUrlKey);
|
||||
|
||||
SetHttpResponseMessageThisRequest(cached);
|
||||
var response = CreateHttpResponseMessage(cached);
|
||||
SetHttpResponseMessageThisRequest(response);
|
||||
|
||||
_logger.LogDebug("finished returned cached response for {downstreamUrlKey}", downstreamUrlKey);
|
||||
|
||||
@ -65,11 +67,50 @@ namespace Ocelot.Cache.Middleware
|
||||
return;
|
||||
}
|
||||
|
||||
var response = HttpResponseMessage;
|
||||
cached = await CreateCachedResponse(HttpResponseMessage);
|
||||
|
||||
_outputCache.Add(downstreamUrlKey, response, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.CacheOptions.TtlSeconds), DownstreamRoute.ReRoute.CacheOptions.Region);
|
||||
_outputCache.Add(downstreamUrlKey, cached, TimeSpan.FromSeconds(DownstreamRoute.ReRoute.CacheOptions.TtlSeconds), DownstreamRoute.ReRoute.CacheOptions.Region);
|
||||
|
||||
_logger.LogDebug("finished response added to cache for {downstreamUrlKey}", downstreamUrlKey);
|
||||
}
|
||||
|
||||
internal HttpResponseMessage CreateHttpResponseMessage(CachedResponse cached)
|
||||
{
|
||||
if (cached == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var response = new HttpResponseMessage(cached.StatusCode);
|
||||
foreach (var header in cached.Headers)
|
||||
{
|
||||
response.Headers.Add(header.Key, header.Value);
|
||||
}
|
||||
var content = new MemoryStream(Convert.FromBase64String(cached.Body));
|
||||
response.Content = new StreamContent(content);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
internal async Task<CachedResponse> CreateCachedResponse(HttpResponseMessage response)
|
||||
{
|
||||
if (response == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var statusCode = response.StatusCode;
|
||||
var headers = response.Headers.ToDictionary(v => v.Key, v => v.Value);
|
||||
string body = null;
|
||||
|
||||
if (response.Content != null)
|
||||
{
|
||||
var content = await response.Content.ReadAsByteArrayAsync();
|
||||
body = Convert.ToBase64String(content);
|
||||
}
|
||||
|
||||
var cached = new CachedResponse(statusCode, headers, body);
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -19,7 +19,7 @@ namespace Ocelot.Configuration
|
||||
List<ClaimToThing> claimsToQueries,
|
||||
string requestIdKey,
|
||||
bool isCached,
|
||||
CacheOptions fileCacheOptions,
|
||||
CacheOptions cacheOptions,
|
||||
string downstreamScheme,
|
||||
string loadBalancer,
|
||||
string downstreamHost,
|
||||
@ -49,7 +49,7 @@ namespace Ocelot.Configuration
|
||||
IsAuthorised = isAuthorised;
|
||||
RequestIdKey = requestIdKey;
|
||||
IsCached = isCached;
|
||||
CacheOptions = fileCacheOptions;
|
||||
CacheOptions = cacheOptions;
|
||||
ClaimsToQueries = claimsToQueries
|
||||
?? new List<ClaimToThing>();
|
||||
ClaimsToClaims = claimsToClaims
|
||||
|
@ -11,9 +11,9 @@ namespace Ocelot.Controllers
|
||||
[Route("outputcache")]
|
||||
public class OutputCacheController : Controller
|
||||
{
|
||||
private IOcelotCache<HttpResponseMessage> _cache;
|
||||
private IOcelotCache<CachedResponse> _cache;
|
||||
|
||||
public OutputCacheController(IOcelotCache<HttpResponseMessage> cache)
|
||||
public OutputCacheController(IOcelotCache<CachedResponse> cache)
|
||||
{
|
||||
_cache = cache;
|
||||
}
|
||||
|
@ -161,13 +161,13 @@ namespace Ocelot.DependencyInjection
|
||||
|
||||
public IOcelotBuilder AddCacheManager(Action<ConfigurationBuilderCachePart> settings)
|
||||
{
|
||||
var cacheManagerOutputCache = CacheFactory.Build<HttpResponseMessage>("OcelotOutputCache", settings);
|
||||
var ocelotOutputCacheManager = new OcelotCacheManagerCache<HttpResponseMessage>(cacheManagerOutputCache);
|
||||
var cacheManagerOutputCache = CacheFactory.Build<CachedResponse>("OcelotOutputCache", settings);
|
||||
var ocelotOutputCacheManager = new OcelotCacheManagerCache<CachedResponse>(cacheManagerOutputCache);
|
||||
|
||||
_services.RemoveAll(typeof(ICacheManager<HttpResponseMessage>));
|
||||
_services.RemoveAll(typeof(IOcelotCache<HttpResponseMessage>));
|
||||
_services.AddSingleton<ICacheManager<HttpResponseMessage>>(cacheManagerOutputCache);
|
||||
_services.AddSingleton<IOcelotCache<HttpResponseMessage>>(ocelotOutputCacheManager);
|
||||
_services.RemoveAll(typeof(ICacheManager<CachedResponse>));
|
||||
_services.RemoveAll(typeof(IOcelotCache<CachedResponse>));
|
||||
_services.AddSingleton<ICacheManager<CachedResponse>>(cacheManagerOutputCache);
|
||||
_services.AddSingleton<IOcelotCache<CachedResponse>>(ocelotOutputCacheManager);
|
||||
|
||||
var ocelotConfigCacheManagerOutputCache = CacheFactory.Build<IOcelotConfiguration>("OcelotConfigurationCache", settings);
|
||||
var ocelotConfigCacheManager = new OcelotCacheManagerCache<IOcelotConfiguration>(ocelotConfigCacheManagerOutputCache);
|
||||
|
Reference in New Issue
Block a user