Browse Source

gateway proxy middleware function maturation

master
Savorboard 7 years ago
parent
commit
152ee4a652
2 changed files with 103 additions and 21 deletions
  1. +102
    -20
      src/DotNetCore.CAP/Dashboard/GatewayProxy/GatewayProxyMiddleware.cs
  2. +1
    -1
      src/DotNetCore.CAP/Dashboard/GatewayProxy/IRequestMapper.Default.cs

+ 102
- 20
src/DotNetCore.CAP/Dashboard/GatewayProxy/GatewayProxyMiddleware.cs View File

@@ -1,18 +1,31 @@
using System; using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using DotNetCore.CAP.Dashboard.GatewayProxy.Requester; using DotNetCore.CAP.Dashboard.GatewayProxy.Requester;
using DotNetCore.CAP.NodeDiscovery;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Primitives;


namespace DotNetCore.CAP.Dashboard.GatewayProxy namespace DotNetCore.CAP.Dashboard.GatewayProxy
{ {
public class GatewayProxyMiddleware : GatewayProxyMiddlewareBase
public class GatewayProxyMiddleware
{ {
private const string NODE_COOKIE_NAME = "cap.node";

private readonly RequestDelegate _next; private readonly RequestDelegate _next;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly IRequestMapper _requestMapper; private readonly IRequestMapper _requestMapper;
private readonly IHttpRequester _requester; private readonly IHttpRequester _requester;


private INodeDiscoveryProvider _discoveryProvider;

protected HttpRequestMessage DownstreamRequest { get; set; }

public GatewayProxyMiddleware(RequestDelegate next, public GatewayProxyMiddleware(RequestDelegate next,
ILoggerFactory loggerFactory, ILoggerFactory loggerFactory,
IRequestMapper requestMapper, IRequestMapper requestMapper,
@@ -24,39 +37,108 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy
_requester = requester; _requester = requester;
} }


public async Task Invoke(HttpContext context, IRequestScopedDataRepository requestScopedDataRepository)
public async Task Invoke(HttpContext context,
DiscoveryOptions discoveryOptions,
INodeDiscoveryProvider discoveryProvider)
{ {
_requestScopedDataRepository = requestScopedDataRepository;
_discoveryProvider = discoveryProvider;


_logger.LogDebug("started calling gateway proxy middleware");
var request = context.Request;
var pathMatch = discoveryOptions.MatchPath;
var isCapRequest = request.Path.StartsWithSegments(
new PathString(pathMatch),
out PathString matchedPath,
out PathString remainingPath);


var downstreamRequest = await _requestMapper.Map(context.Request);
var isSwitchNode = request.Cookies.TryGetValue(NODE_COOKIE_NAME, out string requestNodeId);
var isCurrentNode = discoveryOptions.NodeId.ToString() == requestNodeId;


_logger.LogDebug("setting downstream request");

SetDownstreamRequest(downstreamRequest);
if (!isCapRequest || !isSwitchNode || isCurrentNode)
{
await _next.Invoke(context);
}
else
{
_logger.LogDebug("started calling gateway proxy middleware");

if (TryGetRemoteNode(requestNodeId, out Node node))
{
try
{
DownstreamRequest = await _requestMapper.Map(request);

SetDownStreamRequestUri(node, request.Path.Value);

var response = await _requester.GetResponse(DownstreamRequest);

await SetResponseOnHttpContext(context, response);
}
catch(Exception ex)
{
_logger.LogError(ex.Message);
}
}
else
{
context.Response.Cookies.Delete(NODE_COOKIE_NAME);
await _next.Invoke(context);
}
}
}


_logger.LogDebug("setting upstream request");
private bool TryGetRemoteNode(string requestNodeId, out Node node)
{
var nodes = _discoveryProvider.GetNodes().GetAwaiter().GetResult();
node = nodes.FirstOrDefault(x => x.Id == requestNodeId);
return node != null;
}


SetUpstreamRequestForThisRequest(DownstreamRequest);
private void SetDownStreamRequestUri(Node node, string requestPath)
{
var uriBuilder = new UriBuilder("http://", node.Address, node.Port, requestPath);
DownstreamRequest.RequestUri = uriBuilder.Uri;
}


var uriBuilder = new UriBuilder(DownstreamRequest.RequestUri)
public async Task SetResponseOnHttpContext(HttpContext context, HttpResponseMessage response)
{
foreach (var httpResponseHeader in response.Content.Headers)
{ {
//Path = dsPath.Data.Value,
//Scheme = DownstreamRoute.ReRoute.DownstreamScheme
};
AddHeaderIfDoesntExist(context, httpResponseHeader);
}


DownstreamRequest.RequestUri = uriBuilder.Uri;
var stringContent = await response.Content.ReadAsStringAsync();
var content = await response.Content.ReadAsByteArrayAsync();

AddHeaderIfDoesntExist(context,
new KeyValuePair<string, IEnumerable<string>>("Content-Length", new[] { content.Length.ToString() }));

context.Response.OnStarting(state =>
{
var httpContext = (HttpContext)state;


_logger.LogDebug("started calling request");
httpContext.Response.StatusCode = (int)response.StatusCode;


var response = await _requester.GetResponse(Request);
return Task.CompletedTask;


_logger.LogDebug("setting http response message");
}, context);


SetHttpResponseMessageThisRequest(response);
using (Stream stream = new MemoryStream(content))
{
if (response.StatusCode != HttpStatusCode.NotModified)
{
await stream.CopyToAsync(context.Response.Body);
}
}
}


_logger.LogDebug("returning to calling middleware");
private static void AddHeaderIfDoesntExist(HttpContext context,
KeyValuePair<string, IEnumerable<string>> httpResponseHeader)
{
if (!context.Response.Headers.ContainsKey(httpResponseHeader.Key))
{
context.Response.Headers.Add(httpResponseHeader.Key,
new StringValues(httpResponseHeader.Value.ToArray()));
}
} }
} }
} }

+ 1
- 1
src/DotNetCore.CAP/Dashboard/GatewayProxy/IRequestMapper.Default.cs View File

@@ -12,7 +12,7 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy
{ {
public class RequestMapper : IRequestMapper public class RequestMapper : IRequestMapper
{ {
private readonly string[] _unsupportedHeaders = { "host" };
private readonly string[] _unsupportedHeaders = { "host", "cookie" };
private const string SchemeDelimiter = "://"; private const string SchemeDelimiter = "://";


public async Task<HttpRequestMessage> Map(HttpRequest request) public async Task<HttpRequestMessage> Map(HttpRequest request)


Loading…
Cancel
Save