Closed skyflyer closed 5 years ago
@skyflyer can you share your program / startup.cs
@TomPallister,
here is a simple repro program: ocelotratelimiterror.zip
I'm running a server on localhost:8000
so that Ocelot can proxy it. And I'm issuing requests from bash with for i in {1..5} ; do curl -i http://localhost:5000/api/ocelot.json ; done
. Alternatively, wrk http://localhost:5000/api/ocelot.json
does the same trick.
FWIW, I'm running this on Mac.
@skyflyer i think this is probably a bug, maybe when Ocelot does the rate limiting it isn't setting something required by the responder middleware.
Hi all,
I am facing the same issue, I have an error in the logs when reaching the rate limit.
There is a NullReferenceException
in the SetResponseOnHttpContext
method of Ocelot.Responder.HttpContextResponder
class. The response
parameter is null.
Here is the stacktrace I got:
Ocelot.Errors.Middleware.ExceptionHandlerMiddleware:Error: requestId: 0HLJ41QOS0LJ1:00000003, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) in C:\src\Ocelot\Responder\HttpContextResponder.cs:line 27
at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) in C:\src\Ocelot\Responder\Middleware\ResponderMiddleware.cs:line 45
at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) in C:\src\Ocelot\Middleware\Pipeline\MapWhenMiddleware.cs:line 40
at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) in C:\src\Ocelot\Errors\Middleware\ExceptionHandlerMiddleware.cs:line 53 RequestId: 0HLJ41QOS0LJ1:00000003, exception: System.NullReferenceException: Object reference not set to an instance of an object.
at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) in C:\src\Ocelot\Responder\HttpContextResponder.cs:line 27
at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) in C:\src\Ocelot\Responder\Middleware\ResponderMiddleware.cs:line 45
at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) in C:\src\Ocelot\Middleware\Pipeline\MapWhenMiddleware.cs:line 40
at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) in C:\src\Ocelot\Errors\Middleware\ExceptionHandlerMiddleware.cs:line 53
I guess the method should not be called when response is null (in the Invoke
method of the Ocelot.Responder.Middleware.ResponderMiddleware
class)
Despite the error message my api is not called when the rate limit is reached, so that's ok on this side.
FWIW, I'm getting a similar exception when trying to return an Unauthorized HttpResponseMessage from a delegating handler.
Code:
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
HttpResponseMessage unauthorizedResult =
new HttpResponseMessage(HttpStatusCode.Unauthorized) { RequestMessage = request };
if (!request.Headers.TryGetValues("someheader", out IEnumerable<string> someheaderValues))
{
TaskCompletionSource<HttpResponseMessage> tsc = new TaskCompletionSource<HttpResponseMessage>();
tsc.SetResult(unauthorizedResult);
return await tsc.Task;
return await base.SendAsync(request, cancellationToken);
}
Stack Trace:
Ocelot.Errors.Middleware.ExceptionHandlerMiddleware:Error: requestId: 0HLJRUNOU5HNK:00000001, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context)
at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context)
at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) RequestId: 0HLJRUNOU5HNK:00000001, exception: System.NullReferenceException: Object reference not set to an instance of an object.
at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context)
at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context)
at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context)
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 1544.0562ms 500
Same issue here:
Error: requestId: 0HLKNSPSC2JI0:0000001F, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context)
at MyCustomCode.Startup.<>c.<<Configure>b__4_3>d.MoveNext() in /src/Startup.cs:line 158
--- End of stack trace from previous location where exception was thrown ---
at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context)
at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) RequestId: 0HLKNSPSC2JI0:0000001F, exception: System.NullReferenceException: Object reference not set to an instance of an object.
at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response)
at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context)
at MyCustomCode.Startup.<>c.<<Configure>b__4_3>d.MoveNext() in /src/Startup.cs:line 158
--- End of stack trace from previous location where exception was thrown ---
at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context)
at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) (test-vergelijken.kpnnetwerk.nl)
Line 158 is inside the PreErrorResponderMiddleware
:
await next.Invoke();
Expected Behavior / New Feature
No errors present in the log file (stdout output)
Actual Behavior / Motivation for New Feature
An error is present in the log output:
Steps to Reproduce the Problem
I have configured a ReRoute with the following config:
I then sent several successive requests to the ocelot gateway and observed the error in the log file:
for i in {1..5} ; do curl -i http://localhost:5000/ ; done
.Full log file:
Full log file
``` Using launch settings from /gateway/src/Foobar.Gateway/Properties/launchSettings.json... Hosting environment: Development Content root path: /gateway/src/Foobar.Gateway Now listening on: http://localhost:5000 Application started. Press Ctrl+C to shut down. info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:5000/ info: Ocelot.Authentication.Middleware.AuthenticationMiddleware[0] requestId: 0HLHFFVQP5L6F:00000001, previousRequestId: no previous request id, message: No authentication needed for / info: Ocelot.Authorisation.Middleware.AuthorisationMiddleware[0] requestId: 0HLHFFVQP5L6F:00000001, previousRequestId: no previous request id, message: /{everything} route does not require user to be authorised info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 349.1088ms 200 text/html; charset=utf-8 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:5000/ info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0] requestId: 0HLHFFVQP5L6G:00000001, previousRequestId: no previous request id, message: Request get:/ from ClientId client has been blocked, quota 1/5s exceeded by 2. Blocked by rule /{everything}, TraceIdentifier 0HLHFFVQP5L6G:00000001. fail: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0] requestId: 0HLHFFVQP5L6G:00000001, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) RequestId: 0HLHFFVQP5L6G:00000001, exception: System.NullReferenceException: Object reference not set to an instance of an object. at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 32.8502ms 429 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:5000/ info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0] requestId: 0HLHFFVQP5L6H:00000001, previousRequestId: no previous request id, message: Request get:/ from ClientId client has been blocked, quota 1/5s exceeded by 3. Blocked by rule /{everything}, TraceIdentifier 0HLHFFVQP5L6H:00000001. fail: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0] requestId: 0HLHFFVQP5L6H:00000001, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) RequestId: 0HLHFFVQP5L6H:00000001, exception: System.NullReferenceException: Object reference not set to an instance of an object. at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 0.9687ms 429 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:5000/ info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0] requestId: 0HLHFFVQP5L6I:00000001, previousRequestId: no previous request id, message: Request get:/ from ClientId client has been blocked, quota 1/5s exceeded by 4. Blocked by rule /{everything}, TraceIdentifier 0HLHFFVQP5L6I:00000001. fail: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0] requestId: 0HLHFFVQP5L6I:00000001, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) RequestId: 0HLHFFVQP5L6I:00000001, exception: System.NullReferenceException: Object reference not set to an instance of an object. at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 1.497ms 429 info: Microsoft.AspNetCore.Hosting.Internal.WebHost[1] Request starting HTTP/1.1 GET http://localhost:5000/ info: Ocelot.RateLimit.Middleware.ClientRateLimitMiddleware[0] requestId: 0HLHFFVQP5L6J:00000001, previousRequestId: no previous request id, message: Request get:/ from ClientId client has been blocked, quota 1/5s exceeded by 5. Blocked by rule /{everything}, TraceIdentifier 0HLHFFVQP5L6J:00000001. fail: Ocelot.Errors.Middleware.ExceptionHandlerMiddleware[0] requestId: 0HLHFFVQP5L6J:00000001, previousRequestId: no previous request id, message: Exception caught in global error handler, exception message: Object reference not set to an instance of an object., exception stack: at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) RequestId: 0HLHFFVQP5L6J:00000001, exception: System.NullReferenceException: Object reference not set to an instance of an object. at Ocelot.Responder.HttpContextResponder.SetResponseOnHttpContext(HttpContext context, DownstreamResponse response) at Ocelot.Responder.Middleware.ResponderMiddleware.Invoke(DownstreamContext context) at Ocelot.Middleware.Pipeline.MapWhenMiddleware.Invoke(DownstreamContext context) at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(DownstreamContext context) info: Microsoft.AspNetCore.Hosting.Internal.WebHost[2] Request finished in 1.9146ms 429 ```According to the documentation, I understand that there is 1 request per 5 seconds allowed. But sending multiple requests in succession does not result in rate limiting.
Specifications