Ocelot custom pipeline middleware

Ocelot is valid and not introduced Kazakhstan, the gateway we all know, if you read the source code will find that its core is made of one pipeline middleware component, of course, this is also one of the highlights Net Core of. A request comes in, it will be registered in accordance with the order processing middleware, today's problem lies in the middleware Ocelot pipeline here, and now there is a demand that wants the data encryption and decryption at the gateway level, front-end will encrypt the data through the gateway when decrypting transmitted downstream, the downstream data is returned back to the front end gateway is encrypted.

Here two intermediate register so wanted to go around pipes Ocelot requests and data processing results. Then press wanted to do, but sad reminder that, Ocelot dealt directly return data to the caller, and did not go middleware pipeline behind it, check the information before we know the middle of next Ocelot not called again after a pipeline pieces, and this egg pain, how do? ?

Ocelot suddenly thought should be extended to allow users to provide custom pipeline middleware it, the answer of course is yes, this article, we will customize a pipeline in the middleware on the Ocelot.

You first need to write your own middleware, you need to inherit OcelotMiddleware:

public class TestResponseMiddleware: OcelotMiddleware
    {
        private readonly OcelotRequestDelegate _next;
        public TestResponseMiddleware(OcelotRequestDelegate next,IOcelotLoggerFactory loggerFactory)
            : base(loggerFactory.CreateLogger<TestResponseMiddleware>())
        {
            _next = next;
        }


        public async Task Invoke(DownstreamContext context)
        {
            if (!context.IsError && context.HttpContext.Request.Method.ToUpper() != "OPTIONS")
            {
                //对返回结果进行加密
                //Logger.LogInformation("");
                if (context.HttpContext.Response != null && context.DownstreamResponse.Content.Headers.ContentLength > 0)
                {
                    var result= await context.DownstreamResponse.Content.ReadAsStringAsync();
                    using (var md5 = MD5.Create())
                    {
                        var md5Result = md5.ComputeHash(Encoding.ASCII.GetBytes(result));
                        var strResult = BitConverter.ToString(md5Result);
                        strResult = strResult.Replace("-", "");
                        context.HttpContext.Response.Body.Write(Encoding.UTF8.GetBytes(strResult));
                    }
                }
            }
            else
            {
                await _next.Invoke(context);
            }
        }
    }

This logic is, after a request to get the result of the MD5 encrypted data, then returns.

Then we create a new class registration, registration ducts designed to create a method middleware:

    public static class TestServiceExtension
    {
        public static IOcelotPipelineBuilder UseTestResponseMiddleware(this IOcelotPipelineBuilder builder)
        {
            return builder.UseMiddleware<TestResponseMiddleware>();
        }
    }

Then is the focus! ! Ocelot we need to look through the source code and find the place where the registration pipeline middleware, and then copy that file-come, put it in your project references, you can be understood as modified the source code to use. Our first look is OcelotMiddlewareExtensions.cs file, here is the call entry Ocelot pipeline middleware, do not believe you UseOcelot extension method:

public static class OcelotMiddlewareExtensions
    {
        public static async Task<IApplicationBuilder> UseOcelot(this IApplicationBuilder builder)
        {
            await builder.UseOcelot(new OcelotPipelineConfiguration());
            return builder;
        }

We look at this another way is CreateOcelotPipeline inside, Ocelot pipeline:

        private static IApplicationBuilder CreateOcelotPipeline(IApplicationBuilder builder, OcelotPipelineConfiguration pipelineConfiguration)
        {
            var pipelineBuilder = new OcelotPipelineBuilder(builder.ApplicationServices);

            pipelineBuilder.BuildOcelotPipeline(pipelineConfiguration);

            var firstDelegate = pipelineBuilder.Build();

            /*
            inject first delegate into first piece of asp.net middleware..maybe not like this
            then because we are updating the http context in ocelot it comes out correct for
            rest of asp.net..
            */

            builder.Properties["analysis.NextMiddlewareName"] = "TransitionToOcelotMiddleware";

            builder.Use(async (context, task) =>
            {
                var downstreamContext = new DownstreamContext(context);
                await firstDelegate.Invoke(downstreamContext);
            });

            return builder;
        }

Can see inside pipelineBuilder.BuildOcelotPipeline (pipelineConfiguration) of this code, which is a method of creating Ocelot pipeline middleware, we want to modify that these two places, this method OcelotPipelineExtensions.cs class file, point to look into:

 public static class OcelotPipelineExtensions
    {
        public static OcelotRequestDelegate BuildCustomeOcelotPipeline(this IOcelotPipelineBuilder builder,
            OcelotPipelineConfiguration pipelineConfiguration)
        {
            // This is registered to catch any global exceptions that are not handled
            // It also sets the Request Id if anything is set globally
            builder.UseExceptionHandlerMiddleware();

            // If the request is for websockets upgrade we fork into a different pipeline
            builder.MapWhen(context => context.HttpContext.WebSockets.IsWebSocketRequest,
                app =>
                {
                    app.UseDownstreamRouteFinderMiddleware();
                    app.UseDownstreamRequestInitialiser();
                    app.UseLoadBalancingMiddleware();
                    app.UseDownstreamUrlCreatorMiddleware();
                    app.UseWebSocketsProxyMiddleware();
                });

            // Allow the user to respond with absolutely anything they want.
            builder.UseIfNotNull(pipelineConfiguration.PreErrorResponderMiddleware);

            // This is registered first so it can catch any errors and issue an appropriate response
            builder.UseResponderMiddleware();

            // Then we get the downstream route information
            builder.UseDownstreamRouteFinderMiddleware();

            // This security module, IP whitelist blacklist, extended security mechanism
            builder.UseSecurityMiddleware();

            //Expand other branch pipes
            if (pipelineConfiguration.MapWhenOcelotPipeline != null)
            {
                foreach (var pipeline in pipelineConfiguration.MapWhenOcelotPipeline)
                {
                    builder.MapWhen(pipeline);
                }
            }

            // Now we have the ds route we can transform headers and stuff?
            builder.UseHttpHeadersTransformationMiddleware();

            // Initialises downstream request
            builder.UseDownstreamRequestInitialiser();

            // We check whether the request is ratelimit, and if there is no continue processing
            builder.UseRateLimiting();

            // This adds or updates the request id (initally we try and set this based on global config in the error handling middleware)
            // If anything was set at global level and we have a different setting at re route level the global stuff will be overwritten
            // This means you can get a scenario where you have a different request id from the first piece of middleware to the request id middleware.
            builder.UseRequestIdMiddleware();

            // Allow pre authentication logic. The idea being people might want to run something custom before what is built in.
            builder.UseIfNotNull(pipelineConfiguration.PreAuthenticationMiddleware);

            // Now we know where the client is going to go we can authenticate them.
            // We allow the ocelot middleware to be overriden by whatever the
            // user wants
            if (pipelineConfiguration.AuthenticationMiddleware == null)
            {
                builder.UseAuthenticationMiddleware();
            }
            else
            {
                builder.Use(pipelineConfiguration.AuthenticationMiddleware);
            }

            // The next thing we do is look at any claims transforms in case this is important for authorisation
            builder.UseClaimsToClaimsMiddleware();

            // Allow pre authorisation logic. The idea being people might want to run something custom before what is built in.
            builder.UseIfNotNull(pipelineConfiguration.PreAuthorisationMiddleware);

            // Now we have authenticated and done any claims transformation we
            // can authorise the request
            // We allow the ocelot middleware to be overriden by whatever the
            // user wants
            if (pipelineConfiguration.AuthorisationMiddleware == null)
            {
                builder.UseAuthorisationMiddleware();
            }
            else
            {
                builder.Use(pipelineConfiguration.AuthorisationMiddleware);
            }

            // Now we can run the claims to headers transformation middleware
            builder.UseClaimsToHeadersMiddleware();

            // Allow the user to implement their own query string manipulation logic
            builder.UseIfNotNull(pipelineConfiguration.PreQueryStringBuilderMiddleware);

            // Now we can run any claims to query string transformation middleware
            builder.UseClaimsToQueryStringMiddleware();

            // Get the load balancer for this request
            builder.UseLoadBalancingMiddleware();

            // This takes the downstream route we retrieved earlier and replaces any placeholders with the variables that should be used
            builder.UseDownstreamUrlCreatorMiddleware();

            // Not sure if this is the best place for this but we use the downstream url
            // as the basis for our cache key.
            builder.UseOutputCacheMiddleware();

            //We fire off the request and set the response on the scoped data repo
            builder.UseHttpRequesterMiddleware();

            //添加自定义测试中间件
         builder.UseTestResponseMiddleware();

            return builder.Build();
        }

        private static void UseIfNotNull(this IOcelotPipelineBuilder builder,
            Func<DownstreamContext, Func<Task>, Task> middleware)
        {
            if (middleware != null)
            {
                builder.Use(middleware);
            }
        }
    }

We can see that in fact one call extension methods, but also what we call middleware, and I finally just write middleware add up, it is marked red there, and now all requests will go on into the Ocelot our middleware deal with the use of the time required to modify OcelotPipelineExtensions.cs class files in their own projects in oh.

 

We're done!

Guess you like

Origin www.cnblogs.com/weiBlog/p/11241535.html