Skip to content

Commit

Permalink
(#21) nuar: add cach for http request downstream handler
Browse files Browse the repository at this point in the history
  • Loading branch information
SaintAngeLs committed Oct 10, 2024
1 parent 87265cb commit 23fa2fb
Showing 1 changed file with 99 additions and 89 deletions.
188 changes: 99 additions & 89 deletions src/Nuar/src/Nuar/Handlers/DownstreamHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,117 +90,127 @@ public async Task HandleAsync(HttpContext context, RouteConfig config)
var response = await SendRequestAsync(executionData);
if (response is null)
{
_logger.LogWarning($"Did not receive HTTP response for: {executionData.Route.Downstream}");
_logger.LogWarning($"Downstream service unavailable: {executionData.Route.Downstream}");

context.Response.StatusCode = StatusCodes.Status503ServiceUnavailable;
context.Response.ContentType = ContentTypeApplicationJson;
await context.Response.WriteAsync(JsonConvert.SerializeObject(new
{
error = "Service Unavailable",
message = $"The downstream service at {executionData.Route.Downstream} is currently unavailable. Please try again later."
}));
return;
}

await WriteResponseAsync(context.Response, response, executionData);
}

private async Task<HttpResponseMessage> SendRequestAsync(ExecutionData executionData)
{
var httpClient = _httpClientFactory.CreateClient("nuar");
var method = (string.IsNullOrWhiteSpace(executionData.Route.DownstreamMethod)
? executionData.Context.Request.Method
: executionData.Route.DownstreamMethod).ToLowerInvariant();
{
var httpClient = _httpClientFactory.CreateClient("nuar");
var method = (string.IsNullOrWhiteSpace(executionData.Route.DownstreamMethod)
? executionData.Context.Request.Method
: executionData.Route.DownstreamMethod).ToLowerInvariant();

// Use the downstream URL as is (constructed with the query string in the DownstreamBuilder)
var downstreamUrl = executionData.Downstream;
var downstreamUrl = executionData.Downstream;

var request = new HttpRequestMessage
{
RequestUri = new Uri(downstreamUrl)
};
var request = new HttpRequestMessage
{
RequestUri = new Uri(downstreamUrl)
};

// Forward request headers if specified
if (executionData.Route.ForwardRequestHeaders == true ||
(_options.ForwardRequestHeaders == true && executionData.Route.ForwardRequestHeaders != false))
{
foreach (var (key, value) in executionData.Context.Request.Headers)
{
request.Headers.TryAddWithoutValidation(key, value.ToArray());
}
}
if (executionData.Route.ForwardRequestHeaders == true ||
(_options.ForwardRequestHeaders == true && executionData.Route.ForwardRequestHeaders != false))
{
foreach (var (key, value) in executionData.Context.Request.Headers)
{
request.Headers.TryAddWithoutValidation(key, value.ToArray());
}
}

// Handle custom request headers
var requestHeaders = executionData.Route.RequestHeaders is null || !executionData.Route.RequestHeaders.Any()
? _options.RequestHeaders
: executionData.Route.RequestHeaders;
var requestHeaders = executionData.Route.RequestHeaders is null || !executionData.Route.RequestHeaders.Any()
? _options.RequestHeaders
: executionData.Route.RequestHeaders;

if (requestHeaders != null)
{
foreach (var (key, value) in requestHeaders)
{
if (!string.IsNullOrWhiteSpace(value))
if (requestHeaders != null)
{
request.Headers.TryAddWithoutValidation(key, value);
continue;
foreach (var (key, value) in requestHeaders)
{
if (!string.IsNullOrWhiteSpace(value))
{
request.Headers.TryAddWithoutValidation(key, value);
continue;
}

if (!executionData.Context.Request.Headers.TryGetValue(key, out var values))
{
continue;
}

request.Headers.TryAddWithoutValidation(key, values.ToArray());
}
}

if (!executionData.Context.Request.Headers.TryGetValue(key, out var values))
var includeBody = false;
switch (method)
{
continue;
case "get":
request.Method = HttpMethod.Get;
break;
case "post":
request.Method = HttpMethod.Post;
includeBody = true;
break;
case "put":
request.Method = HttpMethod.Put;
includeBody = true;
break;
case "patch":
request.Method = HttpMethod.Patch;
includeBody = true;
break;
case "delete":
request.Method = HttpMethod.Delete;
break;
case "head":
request.Method = HttpMethod.Head;
break;
case "options":
request.Method = HttpMethod.Options;
break;
case "trace":
request.Method = HttpMethod.Trace;
break;
default:
return null;
}

request.Headers.TryAddWithoutValidation(key, values.ToArray());
}
}
if (_httpRequestHooks != null)
{
foreach (var hook in _httpRequestHooks)
{
if (hook == null) continue;
await hook.InvokeAsync(request, executionData);
}
}

var includeBody = false;
switch (method)
{
case "get":
request.Method = HttpMethod.Get;
break;
case "post":
request.Method = HttpMethod.Post;
includeBody = true;
break;
case "put":
request.Method = HttpMethod.Put;
includeBody = true;
break;
case "patch":
request.Method = HttpMethod.Patch;
includeBody = true;
break;
case "delete":
request.Method = HttpMethod.Delete;
break;
case "head":
request.Method = HttpMethod.Head;
break;
case "options":
request.Method = HttpMethod.Options;
break;
case "trace":
request.Method = HttpMethod.Trace;
break;
default:
return null;
}
try
{
if (!includeBody)
{
return await httpClient.SendAsync(request);
}

// Invoke any HTTP request hooks
if (_httpRequestHooks != null)
{
foreach (var hook in _httpRequestHooks)
{
if (hook == null) continue;
await hook.InvokeAsync(request, executionData);
using var content = GetHttpContent(executionData);
request.Content = content;
return await httpClient.SendAsync(request);
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, $"Failed to reach downstream service: {executionData.Route.Downstream}");
return null;
}
}
}

// Include body content if required (e.g., for POST, PUT, PATCH requests)
if (!includeBody)
{
return await httpClient.SendAsync(request);
}

using var content = GetHttpContent(executionData);
request.Content = content;
return await httpClient.SendAsync(request);
}



Expand Down

0 comments on commit 23fa2fb

Please sign in to comment.