mirror of
				https://github.com/nsnail/Ocelot.git
				synced 2025-11-01 05:55:27 +08:00 
			
		
		
		
	some tidying up and a bit of refactoring...not too happy about how the proxy is working at the moment! May need a rethink!
This commit is contained in:
		| @@ -1,11 +1,24 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Threading.Tasks; | ||||
| using System.Collections.Generic; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| { | ||||
|     public class ConfigurationValidationResult | ||||
|     { | ||||
|         public ConfigurationValidationResult(bool isError) | ||||
|         { | ||||
|             IsError = isError; | ||||
|             Errors = new List<Error>(); | ||||
|         } | ||||
|  | ||||
|         public ConfigurationValidationResult(bool isError, List<Error> errors) | ||||
|         { | ||||
|             IsError = isError; | ||||
|             Errors = errors; | ||||
|         } | ||||
|  | ||||
|         public bool IsError { get; private set; } | ||||
|  | ||||
|         public List<Error> Errors { get; private set; }  | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,5 @@ | ||||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using System.Collections.Generic; | ||||
| using System.Linq; | ||||
| using System.Text; | ||||
| using Ocelot.Library.Infrastructure.Responses; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Configuration | ||||
| @@ -19,7 +17,7 @@ namespace Ocelot.Library.Infrastructure.Configuration | ||||
|  | ||||
|             if (duplicateUpstreamTemplates.Count <= 0) | ||||
|             { | ||||
|                 return new OkResponse<ConfigurationValidationResult>(new ConfigurationValidationResult()); | ||||
|                 return new OkResponse<ConfigurationValidationResult>(new ConfigurationValidationResult(false)); | ||||
|             } | ||||
|                  | ||||
|             var errors = new List<Error>(); | ||||
| @@ -31,7 +29,7 @@ namespace Ocelot.Library.Infrastructure.Configuration | ||||
|                 errors.Add(error); | ||||
|             } | ||||
|  | ||||
|             return new ErrorResponse<ConfigurationValidationResult>(errors); | ||||
|             return new OkResponse<ConfigurationValidationResult>(new ConfigurationValidationResult(true, errors)); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -18,7 +18,6 @@ namespace Ocelot.Library.Infrastructure.DownstreamRouteFinder | ||||
|  | ||||
|         public Response<DownstreamRoute> FindDownstreamRoute(string upstreamUrlPath) | ||||
|         { | ||||
|  | ||||
|             foreach (var template in _configuration.Value.ReRoutes) | ||||
|             { | ||||
|                 var urlMatch = _urlMatcher.Match(upstreamUrlPath, template.UpstreamTemplate); | ||||
|   | ||||
| @@ -0,0 +1,21 @@ | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Requester | ||||
| { | ||||
|     public class HttpClientHttpRequester : IHttpRequester | ||||
|     { | ||||
|         public async Task<HttpResponseMessage> GetResponse(string httpMethod, string downstreamUrl) | ||||
|         { | ||||
|             var method = new HttpMethod(httpMethod); | ||||
|  | ||||
|             var httpRequestMessage = new HttpRequestMessage(method, downstreamUrl); | ||||
|  | ||||
|             using (var httpClient = new HttpClient()) | ||||
|             { | ||||
|                 var response = await httpClient.SendAsync(httpRequestMessage); | ||||
|                 return response; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,11 @@ | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Flurl.Http; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Requester | ||||
| { | ||||
|     public interface IHttpRequester | ||||
|     { | ||||
|         Task<HttpResponseMessage> GetResponse(string httpMethod, string downstreamUrl); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| using System.Net; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Responder | ||||
| { | ||||
|     public class HttpContextResponder : IHttpResponder | ||||
|     { | ||||
|         public async Task<HttpContext> CreateSuccessResponse(HttpContext context, HttpResponseMessage response) | ||||
|         { | ||||
|             if (!response.IsSuccessStatusCode) | ||||
|             { | ||||
|                 context.Response.StatusCode = (int)response.StatusCode; | ||||
|                 return context; | ||||
|             } | ||||
|             await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); | ||||
|             return context; | ||||
|         } | ||||
|  | ||||
|         public async Task<HttpContext> CreateNotFoundResponse(HttpContext context) | ||||
|         { | ||||
|             context.Response.StatusCode = (int)HttpStatusCode.NotFound; | ||||
|             return context; | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,13 @@ | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
|  | ||||
| namespace Ocelot.Library.Infrastructure.Responder | ||||
| { | ||||
|     public interface IHttpResponder | ||||
|     { | ||||
|         Task<HttpContext> CreateSuccessResponse(HttpContext context, HttpResponseMessage response); | ||||
|         Task<HttpContext> CreateNotFoundResponse(HttpContext context); | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -5,7 +5,7 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer | ||||
| { | ||||
|     public class DownstreamUrlTemplateVariableReplacer : IDownstreamUrlTemplateVariableReplacer | ||||
|     { | ||||
|         public string ReplaceTemplateVariable(DownstreamRoute downstreamRoute) | ||||
|         public string ReplaceTemplateVariables(DownstreamRoute downstreamRoute) | ||||
|         { | ||||
|             var upstreamUrl = new StringBuilder(); | ||||
|  | ||||
|   | ||||
| @@ -5,6 +5,6 @@ namespace Ocelot.Library.Infrastructure.UrlTemplateReplacer | ||||
| { | ||||
|     public interface IDownstreamUrlTemplateVariableReplacer | ||||
|     { | ||||
|         string ReplaceTemplateVariable(DownstreamRoute downstreamRoute);    | ||||
|         string ReplaceTemplateVariables(DownstreamRoute downstreamRoute);    | ||||
|     } | ||||
| } | ||||
| @@ -1,10 +1,10 @@ | ||||
| using System.Net; | ||||
| using System.Net.Http; | ||||
| using System.Threading.Tasks; | ||||
| using Microsoft.AspNetCore.Http; | ||||
| using Microsoft.Extensions.Options; | ||||
| using Ocelot.Library.Infrastructure.Configuration; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Requester; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Infrastructure.UrlTemplateReplacer; | ||||
|  | ||||
| namespace Ocelot.Library.Middleware | ||||
| @@ -15,16 +15,22 @@ namespace Ocelot.Library.Middleware | ||||
|         private readonly IDownstreamUrlTemplateVariableReplacer _urlReplacer; | ||||
|         private readonly IOptions<Configuration> _configuration; | ||||
|         private readonly IDownstreamRouteFinder _downstreamRouteFinder; | ||||
|         private readonly IHttpRequester _requester; | ||||
|         private readonly IHttpResponder _responder; | ||||
|  | ||||
|         public ProxyMiddleware(RequestDelegate next,  | ||||
|             IDownstreamUrlTemplateVariableReplacer urlReplacer,  | ||||
|             IOptions<Configuration> configuration,  | ||||
|             IDownstreamRouteFinder downstreamRouteFinder) | ||||
|             IDownstreamRouteFinder downstreamRouteFinder,  | ||||
|             IHttpRequester requester,  | ||||
|             IHttpResponder responder) | ||||
|         { | ||||
|             _next = next; | ||||
|             _urlReplacer = urlReplacer; | ||||
|             _configuration = configuration; | ||||
|             _downstreamRouteFinder = downstreamRouteFinder; | ||||
|             _requester = requester; | ||||
|             _responder = responder; | ||||
|         } | ||||
|  | ||||
|         public async Task Invoke(HttpContext context) | ||||
| @@ -35,27 +41,15 @@ namespace Ocelot.Library.Middleware | ||||
|  | ||||
|             if (downstreamRoute.IsError) | ||||
|             { | ||||
|                 context.Response.StatusCode = (int)HttpStatusCode.NotFound; | ||||
|                 await _responder.CreateNotFoundResponse(context); | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             var downstreamUrl = _urlReplacer.ReplaceTemplateVariable(downstreamRoute.Data); | ||||
|             var downstreamUrl = _urlReplacer.ReplaceTemplateVariables(downstreamRoute.Data); | ||||
|  | ||||
|             using (var httpClient = new HttpClient()) | ||||
|             { | ||||
|                 var httpMethod = new HttpMethod(context.Request.Method); | ||||
|             var response = await _requester.GetResponse(context.Request.Method, downstreamUrl); | ||||
|  | ||||
|                 var httpRequestMessage = new HttpRequestMessage(httpMethod, downstreamUrl); | ||||
|  | ||||
|                 var response = await httpClient.SendAsync(httpRequestMessage); | ||||
|  | ||||
|                 if (!response.IsSuccessStatusCode) | ||||
|                 { | ||||
|                     context.Response.StatusCode = (int)response.StatusCode; | ||||
|                     return; | ||||
|                 } | ||||
|                 await context.Response.WriteAsync(await response.Content.ReadAsStringAsync()); | ||||
|             } | ||||
|             context = await _responder.CreateSuccessResponse(context, response); | ||||
|  | ||||
|             await _next.Invoke(context); | ||||
|         } | ||||
|   | ||||
| @@ -17,7 +17,8 @@ | ||||
|         "Microsoft.Extensions.Logging.Debug": "1.0.0", | ||||
|         "Microsoft.Extensions.Options.ConfigurationExtensions": "1.0.0", | ||||
|         "Microsoft.AspNetCore.Http": "1.0.0", | ||||
|     "YamlDotNet": "3.9.0" | ||||
|         "YamlDotNet": "3.9.0", | ||||
|         "Flurl.Http": "1.0.1" | ||||
|     }, | ||||
|  | ||||
|     "frameworks": { | ||||
|   | ||||
| @@ -4,6 +4,8 @@ using Microsoft.Extensions.Configuration; | ||||
| using Microsoft.Extensions.DependencyInjection; | ||||
| using Microsoft.Extensions.Logging; | ||||
| using Ocelot.Library.Infrastructure.DownstreamRouteFinder; | ||||
| using Ocelot.Library.Infrastructure.Requester; | ||||
| using Ocelot.Library.Infrastructure.Responder; | ||||
| using Ocelot.Library.Middleware; | ||||
|  | ||||
| namespace Ocelot | ||||
| @@ -38,6 +40,8 @@ namespace Ocelot | ||||
|             services.AddSingleton<IUrlPathToUrlTemplateMatcher, UrlPathToUrlTemplateMatcher>(); | ||||
|             services.AddSingleton<IDownstreamUrlTemplateVariableReplacer, DownstreamUrlTemplateVariableReplacer>(); | ||||
|             services.AddSingleton<IDownstreamRouteFinder, DownstreamRouteFinder>(); | ||||
|             services.AddSingleton<IHttpRequester, HttpClientHttpRequester>(); | ||||
|             services.AddSingleton<IHttpResponder, HttpContextResponder>(); | ||||
|         } | ||||
|  | ||||
|         // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. | ||||
|   | ||||
| @@ -20,16 +20,19 @@ namespace Ocelot.AcceptanceTests | ||||
|         private TestServer _server; | ||||
|         private HttpClient _client; | ||||
|         private HttpResponseMessage _response; | ||||
|         private readonly string _configurationPath; | ||||
|  | ||||
|         public OcelotTests() | ||||
|         { | ||||
|             _configurationPath = "./bin/Debug/netcoreapp1.0/configuration.yaml"; | ||||
|             _fakeService = new FakeService(); | ||||
|         } | ||||
|  | ||||
|         [Fact] | ||||
|         public void should_return_response_404() | ||||
|         { | ||||
|             this.Given(x => x.GivenTheApiGatewayIsRunning()) | ||||
|             this.Given(x => x.GivenThereIsAConfiguration(new Configuration())) | ||||
|                 .And(x => x.GivenTheApiGatewayIsRunning()) | ||||
|                 .When(x => x.WhenIRequestTheUrlOnTheApiGateway("/")) | ||||
|                 .Then(x => x.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound)) | ||||
|                 .BDDfy(); | ||||
| @@ -72,12 +75,12 @@ namespace Ocelot.AcceptanceTests | ||||
|         { | ||||
|             var serializer = new Serializer(); | ||||
|  | ||||
|             if (File.Exists("./configuration.yaml")) | ||||
|             if (File.Exists(_configurationPath)) | ||||
|             { | ||||
|                 File.Delete("./configuration.yaml"); | ||||
|                 File.Delete(_configurationPath); | ||||
|             } | ||||
|  | ||||
|             using (TextWriter writer = File.CreateText("./configuration.yaml")) | ||||
|             using (TextWriter writer = File.CreateText(_configurationPath)) | ||||
|             { | ||||
|                 serializer.Serialize(writer, configuration); | ||||
|             } | ||||
|   | ||||
| @@ -58,6 +58,7 @@ namespace Ocelot.UnitTests | ||||
|             })) | ||||
|                 .When(x => x.WhenIValidateTheConfiguration()) | ||||
|                 .Then(x => x.ThenTheResultIsNotValid()) | ||||
|                 .And(x => x.ThenTheErrorIs<DownstreamTemplateAlreadyUsedError>()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
|  | ||||
| @@ -73,12 +74,17 @@ namespace Ocelot.UnitTests | ||||
|  | ||||
|         private void ThenTheResultIsValid() | ||||
|         { | ||||
|             _result.IsError.ShouldBeFalse(); | ||||
|             _result.Data.IsError.ShouldBeFalse(); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheResultIsNotValid() | ||||
|         { | ||||
|             _result.IsError.ShouldBeTrue(); | ||||
|             _result.Data.IsError.ShouldBeTrue(); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheErrorIs<T>() | ||||
|         { | ||||
|             _result.Data.Errors[0].ShouldBeOfType<T>(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -35,21 +35,21 @@ namespace Ocelot.UnitTests | ||||
|         [Fact] | ||||
|         public void should_return_route() | ||||
|         { | ||||
|             this.Given(x => x.GivenThereIsAnUpstreamUrlPath("somePath")) | ||||
|             this.Given(x => x.GivenThereIsAnUpstreamUrlPath("someUpstreamPath")) | ||||
|                 .And(x => x.GivenTheConfigurationIs(new Configuration { | ||||
|                     ReRoutes = new List<ReRoute> | ||||
|                     { | ||||
|                         new ReRoute() | ||||
|                         { | ||||
|                             UpstreamTemplate = "somePath", | ||||
|                             DownstreamTemplate = "somPath" | ||||
|                             UpstreamTemplate = "someUpstreamPath", | ||||
|                             DownstreamTemplate = "someDownstreamPath" | ||||
|                         } | ||||
|                     } | ||||
|                 })) | ||||
|                 .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List<TemplateVariableNameAndValue>(), "somePath"))) | ||||
|                 .And(x => x.GivenTheUrlMatcherReturns(new UrlMatch(true, new List<TemplateVariableNameAndValue>(), "someDownstreamPath"))) | ||||
|                 .When(x => x.WhenICallTheFinder()) | ||||
|                 .Then( | ||||
|                     x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "somePath"))) | ||||
|                     x => x.ThenTheFollowingIsReturned(new DownstreamRoute(new List<TemplateVariableNameAndValue>(), "someDownstreamPath"))) | ||||
|                 .And(x => x.ThenTheUrlMatcherIsCalledCorrectly()) | ||||
|                 .BDDfy(); | ||||
|         } | ||||
| @@ -117,6 +117,7 @@ namespace Ocelot.UnitTests | ||||
|         private void ThenTheFollowingIsReturned(DownstreamRoute expected) | ||||
|         { | ||||
|             _result.Data.DownstreamUrlTemplate.ShouldBe(expected.DownstreamUrlTemplate); | ||||
|  | ||||
|             for (int i = 0; i < _result.Data.TemplateVariableNameAndValues.Count; i++) | ||||
|             { | ||||
|                 _result.Data.TemplateVariableNameAndValues[i].TemplateVariableName.ShouldBe( | ||||
|   | ||||
| @@ -131,7 +131,7 @@ namespace Ocelot.UnitTests | ||||
|  | ||||
|         private void WhenIReplaceTheTemplateVariables() | ||||
|         { | ||||
|             _result = _downstreamUrlPathReplacer.ReplaceTemplateVariable(_downstreamRoute); | ||||
|             _result = _downstreamUrlPathReplacer.ReplaceTemplateVariables(_downstreamRoute); | ||||
|         } | ||||
|  | ||||
|         private void ThenTheDownstreamUrlPathIsReturned(string expected) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 TomPallister
					TomPallister