mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-23 00:52:51 +08:00
fixed problems where routes were not mathing
This commit is contained in:
parent
2103c60d4a
commit
536db48049
@ -122,6 +122,8 @@ Ocelot's primary functionality is to take incomeing http requests and forward th
|
||||
to a downstream service. At the moment in the form of another http request (in the future
|
||||
this could be any transport mechanism.).
|
||||
|
||||
Ocelot always adds a trailing slash to an UpstreamTemplate.
|
||||
|
||||
Ocelot's describes the routing of one request to another as a ReRoute. In order to get
|
||||
anything working in Ocelot you need to set up a ReRoute in the configuration.
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
{
|
||||
"ReRoutes": [
|
||||
{
|
||||
# The url we are forwarding the request to
|
||||
"UpstreamTemplate": "/identityserverexample",
|
||||
# The path we are listening on for this re route
|
||||
# The url we are forwarding the request to, ocelot will not add a trailing slash
|
||||
"DownstreamTemplate": "http://somehost.com/identityserverexample",
|
||||
# The path we are listening on for this re route, Ocelot will add a trailing slash to
|
||||
# this property. Then when a request is made Ocelot makes sure a trailing slash is added
|
||||
# to that so everything matches
|
||||
"UpstreamTemplate": "/identityserverexample",
|
||||
# The method we are listening for on this re route
|
||||
"UpstreamHttpMethod": "Get",
|
||||
|
@ -7,6 +7,7 @@ using Ocelot.Configuration.File;
|
||||
using Ocelot.Configuration.Parser;
|
||||
using Ocelot.Configuration.Validator;
|
||||
using Ocelot.Responses;
|
||||
using Ocelot.Utilities;
|
||||
|
||||
namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
@ -90,7 +91,6 @@ namespace Ocelot.Configuration.Creator
|
||||
? globalConfiguration.RequestIdKey
|
||||
: reRoute.RequestIdKey;
|
||||
|
||||
|
||||
if (isAuthenticated)
|
||||
{
|
||||
var authOptionsForRoute = new AuthenticationOptions(reRoute.AuthenticationOptions.Provider,
|
||||
@ -120,6 +120,8 @@ namespace Ocelot.Configuration.Creator
|
||||
{
|
||||
var upstreamTemplate = reRoute.UpstreamTemplate;
|
||||
|
||||
upstreamTemplate = upstreamTemplate.SetLastCharacterAs('/');
|
||||
|
||||
var placeholders = new List<string>();
|
||||
|
||||
for (var i = 0; i < upstreamTemplate.Length; i++)
|
||||
@ -138,9 +140,11 @@ namespace Ocelot.Configuration.Creator
|
||||
upstreamTemplate = upstreamTemplate.Replace(placeholder, RegExMatchEverything);
|
||||
}
|
||||
|
||||
return reRoute.ReRouteIsCaseSensitive
|
||||
var route = reRoute.ReRouteIsCaseSensitive
|
||||
? $"{upstreamTemplate}{RegExMatchEndString}"
|
||||
: $"{RegExIgnoreCase}{upstreamTemplate}{RegExMatchEndString}";
|
||||
|
||||
return route;
|
||||
}
|
||||
|
||||
private List<ClaimToThing> GetAddThingsToRequest(Dictionary<string,string> thingBeingAdded)
|
||||
|
@ -5,6 +5,7 @@ using Ocelot.DownstreamRouteFinder.Finder;
|
||||
using Ocelot.Infrastructure.RequestData;
|
||||
using Ocelot.Logging;
|
||||
using Ocelot.Middleware;
|
||||
using Ocelot.Utilities;
|
||||
|
||||
namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
{
|
||||
@ -29,7 +30,7 @@ namespace Ocelot.DownstreamRouteFinder.Middleware
|
||||
{
|
||||
_logger.LogDebug("started calling downstream route finder middleware");
|
||||
|
||||
var upstreamUrlPath = context.Request.Path.ToString();
|
||||
var upstreamUrlPath = context.Request.Path.ToString().SetLastCharacterAs('/');
|
||||
|
||||
_logger.LogDebug("upstream url path is {upstreamUrlPath}", upstreamUrlPath);
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
@ -46,14 +47,16 @@ namespace Ocelot.Errors.Middleware
|
||||
_logger.LogDebug("ocelot pipeline finished");
|
||||
}
|
||||
|
||||
private static async Task SetInternalServerErrorOnResponse(HttpContext context)
|
||||
private async Task SetInternalServerErrorOnResponse(HttpContext context)
|
||||
{
|
||||
context.Response.OnStarting(x =>
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
context.Response.ContentType = "application/json";
|
||||
await context.Response.WriteAsync("Internal Server Error");
|
||||
return Task.CompletedTask;
|
||||
}, context);
|
||||
}
|
||||
|
||||
private static string CreateMessage(HttpContext context, Exception e)
|
||||
private string CreateMessage(HttpContext context, Exception e)
|
||||
{
|
||||
var message =
|
||||
$"Exception caught in global error handler, exception message: {e.Message}, exception stack: {e.StackTrace}";
|
||||
|
17
src/Ocelot/Utilities/StringExtensions.cs
Normal file
17
src/Ocelot/Utilities/StringExtensions.cs
Normal file
@ -0,0 +1,17 @@
|
||||
namespace Ocelot.Utilities
|
||||
{
|
||||
public static class StringExtensions
|
||||
{
|
||||
public static string SetLastCharacterAs(this string valueToSetLastChar,
|
||||
char expectedLastChar)
|
||||
{
|
||||
var last = valueToSetLastChar[valueToSetLastChar.Length - 1];
|
||||
|
||||
if (last != expectedLastChar)
|
||||
{
|
||||
valueToSetLastChar = $"{valueToSetLastChar}{expectedLastChar}";
|
||||
}
|
||||
return valueToSetLastChar;
|
||||
}
|
||||
}
|
||||
}
|
@ -56,6 +56,80 @@ namespace Ocelot.AcceptanceTests
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_care_about_no_trailing()
|
||||
{
|
||||
var configuration = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
DownstreamTemplate = "http://localhost:51879/products",
|
||||
UpstreamTemplate = "/products/",
|
||||
UpstreamHttpMethod = "Get",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/products", 200, "Hello from Laura"))
|
||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||
.And(x => _steps.GivenOcelotIsRunning())
|
||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/products"))
|
||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_not_care_about_trailing()
|
||||
{
|
||||
var configuration = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
DownstreamTemplate = "http://localhost:51879/products",
|
||||
UpstreamTemplate = "/products",
|
||||
UpstreamHttpMethod = "Get",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/products", 200, "Hello from Laura"))
|
||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||
.And(x => _steps.GivenOcelotIsRunning())
|
||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
|
||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||
.And(x => _steps.ThenTheResponseBodyShouldBe("Hello from Laura"))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_not_found()
|
||||
{
|
||||
var configuration = new FileConfiguration
|
||||
{
|
||||
ReRoutes = new List<FileReRoute>
|
||||
{
|
||||
new FileReRoute
|
||||
{
|
||||
DownstreamTemplate = "http://localhost:51879/products",
|
||||
UpstreamTemplate = "/products/{productId}",
|
||||
UpstreamHttpMethod = "Get",
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879/products", 200, "Hello from Laura"))
|
||||
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||
.And(x => _steps.GivenOcelotIsRunning())
|
||||
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/products/"))
|
||||
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.NotFound))
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void should_return_response_200_with_complex_url()
|
||||
{
|
||||
|
@ -137,6 +137,12 @@
|
||||
"UpstreamTemplate": "/customers/{customerId}",
|
||||
"UpstreamHttpMethod": "Delete",
|
||||
"FileCacheOptions": { "TtlSeconds": 15 }
|
||||
},
|
||||
{
|
||||
"DownstreamTemplate": "http://jsonplaceholder.typicode.com/posts",
|
||||
"UpstreamTemplate": "/posts/",
|
||||
"UpstreamHttpMethod": "Get",
|
||||
"FileCacheOptions": { "TtlSeconds": 15 }
|
||||
}
|
||||
],
|
||||
"GlobalConfiguration": {
|
||||
|
@ -59,7 +59,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("(?i)/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
|
||||
.Build()
|
||||
}))
|
||||
.BDDfy();
|
||||
@ -88,7 +88,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("(?i)/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("(?i)/api/products/.*/$")
|
||||
.Build()
|
||||
}))
|
||||
.BDDfy();
|
||||
@ -118,7 +118,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/$")
|
||||
.Build()
|
||||
}))
|
||||
.BDDfy();
|
||||
@ -152,7 +152,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/$")
|
||||
.WithRequestIdKey("blahhhh")
|
||||
.Build()
|
||||
}))
|
||||
@ -183,7 +183,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/$")
|
||||
.Build()
|
||||
}))
|
||||
.BDDfy();
|
||||
@ -198,7 +198,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/$")
|
||||
.WithAuthenticationProvider("IdentityServer")
|
||||
.WithAuthenticationProviderUrl("http://localhost:51888")
|
||||
.WithRequireHttps(false)
|
||||
@ -261,7 +261,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*$")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/$")
|
||||
.WithAuthenticationProvider("IdentityServer")
|
||||
.WithAuthenticationProviderUrl("http://localhost:51888")
|
||||
.WithRequireHttps(false)
|
||||
@ -323,7 +323,7 @@ namespace Ocelot.UnitTests.Configuration
|
||||
.WithDownstreamTemplate("/products/{productId}")
|
||||
.WithUpstreamTemplate("/api/products/{productId}/variants/{variantId}")
|
||||
.WithUpstreamHttpMethod("Get")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/variants/.*$")
|
||||
.WithUpstreamTemplatePattern("/api/products/.*/variants/.*/$")
|
||||
.Build()
|
||||
}))
|
||||
.BDDfy();
|
||||
|
@ -148,7 +148,6 @@ namespace Ocelot.UnitTests.DownstreamRouteFinder.UrlMatcher
|
||||
.BDDfy();
|
||||
}
|
||||
|
||||
|
||||
private void GivenIHaveAUpstreamPath(string downstreamPath)
|
||||
{
|
||||
_downstreamUrlPath = downstreamPath;
|
||||
|
Loading…
x
Reference in New Issue
Block a user