ThreeMammals / Ocelot

.NET API Gateway
https://www.nuget.org/packages/Ocelot
MIT License
8.32k stars 1.63k forks source link

Return custom status code #1511

Closed jpcarpanezi closed 3 months ago

jpcarpanezi commented 3 years ago

Expected Behavior

Actual Behavior

requestId: 4000000b-0000-fb00-b63f-84710c7967bb, 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(HttpContext httpContext)
         at Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
         at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
         at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(HttpContext httpContext) RequestId: 4000000b-0000-fb00-b63f-84710c7967bb, 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(HttpContext httpContext)
         at Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
         at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
         at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(HttpContext httpContext)
      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(HttpContext httpContext)
         at Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
         at Microsoft.AspNetCore.Builder.Extensions.MapWhenMiddleware.Invoke(HttpContext context)
         at Microsoft.AspNetCore.MiddlewareAnalysis.AnalysisMiddleware.Invoke(HttpContext httpContext)
         at Ocelot.Errors.Middleware.ExceptionHandlerMiddleware.Invoke(HttpContext httpContext)

Steps to Reproduce the Problem

  1. Add OcelotPipelineConfiguration in Startup.cs Configure method

    var configuration = new OcelotPipelineConfiguration {
    PreAuthorizationMiddleware = async (ctx, next) => {
        string token = ctx.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
    
        if (!string.IsNullOrEmpty(token)) {
            string blacklist = await cache.GetStringAsync(token);
    
            if (string.IsNullOrEmpty(blacklist)) {
                ctx.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
                await ctx.Response.WriteAsync("Não");
                return;
            }
        }
    
                await next.Invoke();
    }
    };
  2. Add pipeline to UseOcelot() method await app.UseOcelot(configuration);

Specifications

raman-m commented 8 months ago

Hi @jpcarpanezi ! Welcome to Ocelot world! 🐯

We know about this problem of original status code overriding by Error Mapper... :disappointed: In docs we have this page: Error Status Codes

This is very ugly and redundant feature which behaves strange, and it breaks a lot of downstream services. We have to recover original status code and keep it in HTTP response. But custom Ocelot status can be moved to a new header.

raman-m commented 3 months ago

Since you return immediately then previous middlewares override status. I recommend to add custom response header with the status value and forget about the problem. Also you could write formatted response body with data to parse on the client's side.