mirror of
https://github.com/nsnail/Ocelot.git
synced 2025-04-20 17:42:50 +08:00
parent
7dbfc46e7b
commit
079ec0f365
@ -1,104 +1,104 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Ocelot.Configuration.Repository;
|
using Ocelot.Configuration.Repository;
|
||||||
using Ocelot.Infrastructure.Extensions;
|
using Ocelot.Infrastructure.Extensions;
|
||||||
using Ocelot.Infrastructure.RequestData;
|
using Ocelot.Infrastructure.RequestData;
|
||||||
using Ocelot.Logging;
|
using Ocelot.Logging;
|
||||||
using Ocelot.Middleware;
|
using Ocelot.Middleware;
|
||||||
|
|
||||||
namespace Ocelot.Errors.Middleware
|
namespace Ocelot.Errors.Middleware
|
||||||
{
|
{
|
||||||
using Configuration;
|
using Configuration;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
|
/// Catches all unhandled exceptions thrown by middleware, logs and returns a 500
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class ExceptionHandlerMiddleware : OcelotMiddleware
|
public class ExceptionHandlerMiddleware : OcelotMiddleware
|
||||||
{
|
{
|
||||||
private readonly OcelotRequestDelegate _next;
|
private readonly OcelotRequestDelegate _next;
|
||||||
private readonly IInternalConfigurationRepository _configRepo;
|
private readonly IInternalConfigurationRepository _configRepo;
|
||||||
private readonly IRequestScopedDataRepository _repo;
|
private readonly IRequestScopedDataRepository _repo;
|
||||||
|
|
||||||
public ExceptionHandlerMiddleware(OcelotRequestDelegate next,
|
public ExceptionHandlerMiddleware(OcelotRequestDelegate next,
|
||||||
IOcelotLoggerFactory loggerFactory,
|
IOcelotLoggerFactory loggerFactory,
|
||||||
IInternalConfigurationRepository configRepo,
|
IInternalConfigurationRepository configRepo,
|
||||||
IRequestScopedDataRepository repo)
|
IRequestScopedDataRepository repo)
|
||||||
: base(loggerFactory.CreateLogger<ExceptionHandlerMiddleware>())
|
: base(loggerFactory.CreateLogger<ExceptionHandlerMiddleware>())
|
||||||
{
|
{
|
||||||
_configRepo = configRepo;
|
_configRepo = configRepo;
|
||||||
_repo = repo;
|
_repo = repo;
|
||||||
_next = next;
|
_next = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task Invoke(DownstreamContext context)
|
public async Task Invoke(DownstreamContext context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
//try and get the global request id and set it for logs...
|
//try and get the global request id and set it for logs...
|
||||||
//should this basically be immutable per request...i guess it should!
|
//should this basically be immutable per request...i guess it should!
|
||||||
//first thing is get config
|
//first thing is get config
|
||||||
var configuration = _configRepo.Get();
|
var configuration = _configRepo.Get();
|
||||||
|
|
||||||
if (configuration.IsError)
|
if (configuration.IsError)
|
||||||
{
|
{
|
||||||
throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
|
throw new Exception($"{MiddlewareName} setting pipeline errors. IOcelotConfigurationProvider returned {configuration.Errors.ToErrorString()}");
|
||||||
}
|
}
|
||||||
|
|
||||||
TrySetGlobalRequestId(context, configuration.Data);
|
TrySetGlobalRequestId(context, configuration.Data);
|
||||||
|
|
||||||
context.Configuration = configuration.Data;
|
context.Configuration = configuration.Data;
|
||||||
|
|
||||||
Logger.LogDebug("ocelot pipeline started");
|
Logger.LogDebug("ocelot pipeline started");
|
||||||
|
|
||||||
await _next.Invoke(context);
|
await _next.Invoke(context);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
Logger.LogDebug("error calling middleware");
|
Logger.LogDebug("error calling middleware");
|
||||||
|
|
||||||
var message = CreateMessage(context, e);
|
var message = CreateMessage(context, e);
|
||||||
|
|
||||||
Logger.LogError(message, e);
|
Logger.LogError(message, e);
|
||||||
|
|
||||||
SetInternalServerErrorOnResponse(context);
|
SetInternalServerErrorOnResponse(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
Logger.LogDebug("ocelot pipeline finished");
|
Logger.LogDebug("ocelot pipeline finished");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TrySetGlobalRequestId(DownstreamContext context, IInternalConfiguration configuration)
|
private void TrySetGlobalRequestId(DownstreamContext context, IInternalConfiguration configuration)
|
||||||
{
|
{
|
||||||
var key = configuration.RequestId;
|
var key = configuration.RequestId;
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
|
if (!string.IsNullOrEmpty(key) && context.HttpContext.Request.Headers.TryGetValue(key, out var upstreamRequestIds))
|
||||||
{
|
{
|
||||||
context.HttpContext.TraceIdentifier = upstreamRequestIds.First();
|
context.HttpContext.TraceIdentifier = upstreamRequestIds.First();
|
||||||
}
|
}
|
||||||
|
|
||||||
_repo.Add("RequestId", context.HttpContext.TraceIdentifier);
|
_repo.Add("RequestId", context.HttpContext.TraceIdentifier);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetInternalServerErrorOnResponse(DownstreamContext context)
|
private void SetInternalServerErrorOnResponse(DownstreamContext context)
|
||||||
{
|
{
|
||||||
if (!context.HttpContext.Response.HasStarted)
|
if (!context.HttpContext.Response.HasStarted)
|
||||||
{
|
{
|
||||||
context.HttpContext.Response.StatusCode = 500;
|
context.HttpContext.Response.StatusCode = 500;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private string CreateMessage(DownstreamContext context, Exception e)
|
private string CreateMessage(DownstreamContext context, Exception e)
|
||||||
{
|
{
|
||||||
var message =
|
var message =
|
||||||
$"Exception caught in global error handler, exception message: {e.Message}, exception stack: {e.StackTrace}";
|
$"Exception caught in global error handler, exception message: {e.Message}, exception stack: {e.StackTrace}";
|
||||||
|
|
||||||
if (e.InnerException != null)
|
if (e.InnerException != null)
|
||||||
{
|
{
|
||||||
message =
|
message =
|
||||||
$"{message}, inner exception message {e.InnerException.Message}, inner exception stack {e.InnerException.StackTrace}";
|
$"{message}, inner exception message {e.InnerException.Message}, inner exception stack {e.InnerException.StackTrace}";
|
||||||
}
|
}
|
||||||
|
|
||||||
return $"{message} RequestId: {context.HttpContext.TraceIdentifier}";
|
return $"{message} RequestId: {context.HttpContext.TraceIdentifier}";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,6 +313,78 @@ namespace Ocelot.AcceptanceTests
|
|||||||
.BDDfy();
|
.BDDfy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void issue_474_should_not_put_spaces_in_header()
|
||||||
|
{
|
||||||
|
var configuration = new FileConfiguration
|
||||||
|
{
|
||||||
|
ReRoutes = new List<FileReRoute>
|
||||||
|
{
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 51879,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpstreamPathTemplate = "/",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Accept"))
|
||||||
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
|
.And(x => _steps.GivenOcelotIsRunning())
|
||||||
|
.And(x => _steps.GivenIAddAHeader("Accept", "text/html,application/xhtml+xml,application/xml;"))
|
||||||
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
||||||
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
|
.And(x => _steps.ThenTheResponseBodyShouldBe("text/html,application/xhtml+xml,application/xml;"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void issue_474_should_put_spaces_in_header()
|
||||||
|
{
|
||||||
|
var configuration = new FileConfiguration
|
||||||
|
{
|
||||||
|
ReRoutes = new List<FileReRoute>
|
||||||
|
{
|
||||||
|
new FileReRoute
|
||||||
|
{
|
||||||
|
DownstreamPathTemplate = "/",
|
||||||
|
DownstreamScheme = "http",
|
||||||
|
DownstreamHostAndPorts = new List<FileHostAndPort>
|
||||||
|
{
|
||||||
|
new FileHostAndPort
|
||||||
|
{
|
||||||
|
Host = "localhost",
|
||||||
|
Port = 51879,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
UpstreamPathTemplate = "/",
|
||||||
|
UpstreamHttpMethod = new List<string> { "Get" },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
this.Given(x => x.GivenThereIsAServiceRunningOn("http://localhost:51879", "/", 200, "Accept"))
|
||||||
|
.And(x => _steps.GivenThereIsAConfiguration(configuration))
|
||||||
|
.And(x => _steps.GivenOcelotIsRunning())
|
||||||
|
.And(x => _steps.GivenIAddAHeader("Accept", "text/html"))
|
||||||
|
.And(x => _steps.GivenIAddAHeader("Accept", "application/xhtml+xml"))
|
||||||
|
.And(x => _steps.GivenIAddAHeader("Accept", "application/xml"))
|
||||||
|
.When(x => _steps.WhenIGetUrlOnTheApiGateway("/"))
|
||||||
|
.Then(x => _steps.ThenTheStatusCodeShouldBe(HttpStatusCode.OK))
|
||||||
|
.And(x => _steps.ThenTheResponseBodyShouldBe("text/html, application/xhtml+xml, application/xml"))
|
||||||
|
.BDDfy();
|
||||||
|
}
|
||||||
|
|
||||||
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
|
private void GivenThereIsAServiceRunningOn(string baseUrl, string basePath, int statusCode)
|
||||||
{
|
{
|
||||||
_builder = new WebHostBuilder()
|
_builder = new WebHostBuilder()
|
||||||
|
@ -746,7 +746,7 @@ namespace Ocelot.AcceptanceTests
|
|||||||
|
|
||||||
public void GivenIAddAHeader(string key, string value)
|
public void GivenIAddAHeader(string key, string value)
|
||||||
{
|
{
|
||||||
_ocelotClient.DefaultRequestHeaders.Add(key, value);
|
_ocelotClient.DefaultRequestHeaders.TryAddWithoutValidation(key, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
|
public void WhenIGetUrlOnTheApiGatewayMultipleTimes(string url, int times)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user