Commit 89e599a3 authored by yangxiaodong's avatar yangxiaodong

update gateway.

parent cf2512b4
using System; namespace DotNetCore.CAP.Dashboard.GatewayProxy
using System.Collections.Generic;
using System.Text;
namespace DotNetCore.CAP.Dashboard.GatewayProxy
{ {
public class DownstreamUrl public class DownstreamUrl
{ {
......
using System.Collections.Generic; using System;
using System.Net.Http; using System.Threading.Tasks;
using DotNetCore.CAP.Dashboard.GatewayProxy.Requester;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace DotNetCore.CAP.Dashboard.GatewayProxy namespace DotNetCore.CAP.Dashboard.GatewayProxy
{ {
public abstract class GatewayProxyMiddleware public class GatewayProxyMiddleware : GatewayProxyMiddlewareBase
{ {
private readonly IRequestScopedDataRepository _requestScopedDataRepository; private readonly RequestDelegate _next;
private readonly ILogger _logger;
private readonly IRequestMapper _requestMapper;
private readonly IHttpRequester _requester;
public GatewayProxyMiddleware(RequestDelegate next,
ILoggerFactory loggerFactory,
IRequestMapper requestMapper,
IHttpRequester requester)
{
_next = next;
_logger = loggerFactory.CreateLogger<GatewayProxyMiddleware>();
_requestMapper = requestMapper;
_requester = requester;
}
protected GatewayProxyMiddleware(IRequestScopedDataRepository requestScopedDataRepository) public async Task Invoke(HttpContext context, IRequestScopedDataRepository requestScopedDataRepository)
{ {
_requestScopedDataRepository = requestScopedDataRepository; _requestScopedDataRepository = requestScopedDataRepository;
MiddlewareName = this.GetType().Name;
}
public string MiddlewareName { get; } _logger.LogDebug("started calling gateway proxy middleware");
//public DownstreamRoute DownstreamRoute => _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute"); var downstreamRequest = await _requestMapper.Map(context.Request);
public HttpRequestMessage Request => _requestScopedDataRepository.Get<HttpRequestMessage>("Request"); _logger.LogDebug("setting downstream request");
public HttpRequestMessage DownstreamRequest => _requestScopedDataRepository.Get<HttpRequestMessage>("DownstreamRequest"); SetDownstreamRequest(downstreamRequest);
public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage"); _logger.LogDebug("setting upstream request");
public void SetUpstreamRequestForThisRequest(HttpRequestMessage request) SetUpstreamRequestForThisRequest(DownstreamRequest);
{
_requestScopedDataRepository.Add("Request", request);
}
public void SetDownstreamRequest(HttpRequestMessage request) var uriBuilder = new UriBuilder(DownstreamRequest.RequestUri)
{ {
_requestScopedDataRepository.Add("DownstreamRequest", request); //Path = dsPath.Data.Value,
} //Scheme = DownstreamRoute.ReRoute.DownstreamScheme
};
public void SetHttpResponseMessageThisRequest(HttpResponseMessage responseMessage) DownstreamRequest.RequestUri = uriBuilder.Uri;
{
_requestScopedDataRepository.Add("HttpResponseMessage", responseMessage); _logger.LogDebug("started calling request");
var response = await _requester.GetResponse(Request);
_logger.LogDebug("setting http response message");
SetHttpResponseMessageThisRequest(response);
_logger.LogDebug("returning to calling middleware");
} }
} }
} }
\ No newline at end of file
using System.Net.Http;
namespace DotNetCore.CAP.Dashboard.GatewayProxy
{
public abstract class GatewayProxyMiddlewareBase
{
protected IRequestScopedDataRepository _requestScopedDataRepository;
protected GatewayProxyMiddlewareBase()
{
MiddlewareName = this.GetType().Name;
}
public string MiddlewareName { get; }
//public DownstreamRoute DownstreamRoute => _requestScopedDataRepository.Get<DownstreamRoute>("DownstreamRoute");
public HttpRequestMessage Request => _requestScopedDataRepository.Get<HttpRequestMessage>("Request");
public HttpRequestMessage DownstreamRequest => _requestScopedDataRepository.Get<HttpRequestMessage>("DownstreamRequest");
public HttpResponseMessage HttpResponseMessage => _requestScopedDataRepository.Get<HttpResponseMessage>("HttpResponseMessage");
public void SetUpstreamRequestForThisRequest(HttpRequestMessage request)
{
_requestScopedDataRepository.Add("Request", request);
}
public void SetDownstreamRequest(HttpRequestMessage request)
{
_requestScopedDataRepository.Add("DownstreamRequest", request);
}
public void SetHttpResponseMessageThisRequest(HttpResponseMessage responseMessage)
{
_requestScopedDataRepository.Add("HttpResponseMessage", responseMessage);
}
}
}
\ No newline at end of file
using System; namespace DotNetCore.CAP.Dashboard.GatewayProxy
using System.Collections.Generic;
using System.Text;
namespace DotNetCore.CAP.Dashboard.GatewayProxy
{ {
public class HostAndPort public class HostAndPort
{ {
......
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Primitives;
namespace DotNetCore.CAP.Dashboard.GatewayProxy
{
public class RequestMapper : IRequestMapper
{
private readonly string[] _unsupportedHeaders = { "host" };
private const string SchemeDelimiter = "://";
public async Task<HttpRequestMessage> Map(HttpRequest request)
{
try
{
var requestMessage = new HttpRequestMessage()
{
Content = await MapContent(request),
Method = MapMethod(request),
RequestUri = MapUri(request)
};
MapHeaders(request, requestMessage);
return requestMessage;
}
catch (Exception ex)
{
throw new Exception($"Error when parsing incoming request, exception: {ex.Message}");
}
}
private async Task<HttpContent> MapContent(HttpRequest request)
{
if (request.Body == null)
{
return null;
}
var content = new ByteArrayContent(await ToByteArray(request.Body));
content.Headers.TryAddWithoutValidation("Content-Type", new[] { request.ContentType });
return content;
}
private HttpMethod MapMethod(HttpRequest request)
{
return new HttpMethod(request.Method);
}
private Uri MapUri(HttpRequest request)
{
return new Uri(GetEncodedUrl(request));
}
private void MapHeaders(HttpRequest request, HttpRequestMessage requestMessage)
{
foreach (var header in request.Headers)
{
//todo get rid of if..
if (IsSupportedHeader(header))
{
requestMessage.Headers.TryAddWithoutValidation(header.Key, header.Value.ToArray());
}
}
}
private async Task<byte[]> ToByteArray(Stream stream)
{
using (stream)
{
using (var memStream = new MemoryStream())
{
await stream.CopyToAsync(memStream);
return memStream.ToArray();
}
}
}
private bool IsSupportedHeader(KeyValuePair<string, StringValues> header)
{
return !_unsupportedHeaders.Contains(header.Key.ToLower());
}
/// <summary>
/// Combines the given URI components into a string that is properly encoded for use in HTTP headers.
/// Note that unicode in the HostString will be encoded as punycode.
/// </summary>
/// <param name="scheme">http, https, etc.</param>
/// <param name="host">The host portion of the uri normally included in the Host header. This may include the port.</param>
/// <param name="pathBase">The first portion of the request path associated with application root.</param>
/// <param name="path">The portion of the request path that identifies the requested resource.</param>
/// <param name="query">The query, if any.</param>
/// <param name="fragment">The fragment, if any.</param>
/// <returns></returns>
public string BuildAbsolute(
string scheme,
HostString host,
PathString pathBase = new PathString(),
PathString path = new PathString(),
QueryString query = new QueryString(),
FragmentString fragment = new FragmentString())
{
if (scheme == null)
{
throw new ArgumentNullException(nameof(scheme));
}
var combinedPath = (pathBase.HasValue || path.HasValue) ? (pathBase + path).ToString() : "/";
var encodedHost = host.ToString();
var encodedQuery = query.ToString();
var encodedFragment = fragment.ToString();
// PERF: Calculate string length to allocate correct buffer size for StringBuilder.
var length = scheme.Length + SchemeDelimiter.Length + encodedHost.Length
+ combinedPath.Length + encodedQuery.Length + encodedFragment.Length;
return new StringBuilder(length)
.Append(scheme)
.Append(SchemeDelimiter)
.Append(encodedHost)
.Append(combinedPath)
.Append(encodedQuery)
.Append(encodedFragment)
.ToString();
}
/// <summary>
/// Returns the combined components of the request URL in a fully escaped form suitable for use in HTTP headers
/// and other HTTP operations.
/// </summary>
/// <param name="request">The request to assemble the uri pieces from.</param>
/// <returns></returns>
public string GetEncodedUrl(HttpRequest request)
{
return BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path, request.QueryString);
}
}
}
\ No newline at end of file
namespace DotNetCore.CAP.Dashboard.GatewayProxy
{
using System.Net.Http;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
public interface IRequestMapper
{
Task<HttpRequestMessage> Map(HttpRequest request);
}
}
\ No newline at end of file
using System;
using System.Collections.Concurrent;
using Microsoft.AspNetCore.Http;
namespace DotNetCore.CAP.Dashboard.GatewayProxy
{
public class HttpDataRepository : IRequestScopedDataRepository
{
private readonly IHttpContextAccessor _httpContextAccessor;
public HttpDataRepository(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void Add<T>(string key, T value)
{
_httpContextAccessor.HttpContext.Items.Add(key, value);
}
public T Get<T>(string key)
{
object obj;
if (_httpContextAccessor.HttpContext.Items.TryGetValue(key, out obj))
{
return (T)obj;
}
throw new Exception($"Unable to find data for key: {key}");
}
}
public class ScopedDataRepository : IRequestScopedDataRepository
{
private readonly ConcurrentDictionary<string, object> dictionary = null;
public ScopedDataRepository()
{
dictionary = new ConcurrentDictionary<string, object>();
}
public void Add<T>(string key, T value)
{
dictionary.AddOrUpdate(key, value, (k, v) => value);
}
public T Get<T>(string key)
{
if (dictionary.TryGetValue(key, out object t))
{
return (T)t;
}
throw new Exception($"Unable to find data for key: {key}");
}
}
}
\ No newline at end of file
using System.Collections.Generic;
namespace DotNetCore.CAP.Dashboard.GatewayProxy namespace DotNetCore.CAP.Dashboard.GatewayProxy
{ {
public interface IRequestScopedDataRepository public interface IRequestScopedDataRepository
{ {
void Add<T>(string key, T value); void Add<T>(string key, T value);
T Get<T>(string key); T Get<T>(string key);
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Net;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
...@@ -22,7 +21,6 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester ...@@ -22,7 +21,6 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler) private HttpMessageHandler CreateHttpMessageHandler(HttpMessageHandler httpMessageHandler)
{ {
_handlers _handlers
.OrderByDescending(handler => handler.Key) .OrderByDescending(handler => handler.Key)
.Select(handler => handler.Value) .Select(handler => handler.Value)
......
using System; using System;
using System.Collections.Concurrent;
using System.Net.Http; using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
...@@ -38,7 +37,6 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester ...@@ -38,7 +37,6 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
{ {
_cacheHandlers.Set(cacheKey, httpClient, TimeSpan.FromHours(24)); _cacheHandlers.Set(cacheKey, httpClient, TimeSpan.FromHours(24));
} }
} }
private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder) private IHttpClient GetHttpClient(string cacheKey, IHttpClientBuilder builder)
......
using System; using System.Net.Http;
using System.Net.Http;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
......
using System; namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Net;
namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
{ {
public interface IHttpClientBuilder public interface IHttpClientBuilder
{ {
......
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
{ {
public interface IHttpClientCache public interface IHttpClientCache
{ {
bool Exists(string id); bool Exists(string id);
IHttpClient Get(string id); IHttpClient Get(string id);
void Remove(string id); void Remove(string id);
void Set(string id, IHttpClient handler, TimeSpan expirationTime); void Set(string id, IHttpClient handler, TimeSpan expirationTime);
} }
} }
\ No newline at end of file
using System; using System;
using System.Collections.Concurrent; using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
{ {
...@@ -34,7 +30,7 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester ...@@ -34,7 +30,7 @@ namespace DotNetCore.CAP.Dashboard.GatewayProxy.Requester
public IHttpClient Get(string id) public IHttpClient Get(string id)
{ {
IHttpClient client= null; IHttpClient client = null;
ConcurrentQueue<IHttpClient> connectionQueue; ConcurrentQueue<IHttpClient> connectionQueue;
if (_httpClientsCache.TryGetValue(id, out connectionQueue)) if (_httpClientsCache.TryGetValue(id, out connectionQueue))
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment