Blazor WebAssembly integrates Ocelot gateway to solve cross-domain problems by the way

Blazor WebAssembly integrates Ocelot gateway to solve cross-domain problems by the way

We know that cross-domain requests are usually blocked by browsers. This is a security mechanism provided by the browser, that is, scripts under one domain name are not allowed to request data from another domain name.

Please note that the ASP.NET Core hosted mode of Blazor WebAssembly is used here, that is, the template has three items: Client, Server, and Share.

Problem Description

I encountered such a problem in the development of blazor applications. My project needs to use six or seven different site interfaces, including unified login site, order interface site, store interface site, three-party channel site and so on. And I hope to get HttpClient to make a request through HttpClientFactory.

As we all know, IHttpClientFactory can be used in many ways:

  • basic usage
  • named client
  • typed client
  • generated client

If we use the named client method, we can easily distinguish HttpClients with different BaseAddresses based on the name, but the company already has a class library that encapsulates the native HttpClient, so I must use the typed client method.

An example is given here (including the addition of HttpMessageHandler in the IOC container):

 public static class ServiceClientExtension
    {
        public static WebAssemblyHostBuilder AddServiceClient(this WebAssemblyHostBuilder builder)
        {
            builder.Services.AddScoped<PlatformRequestHandler>();
            builder.Services
                .AddHttpClient<IServiceClient, ServiceClients.ServiceClient>((sp, client) =>
                {
                    var option = sp.GetService<ModuleOption>();
                    if (string.IsNullOrWhiteSpace(option.BaseAddress))
                    {
                        option.BaseAddress = builder.HostEnvironment.BaseAddress;
                    }
                    client.BaseAddress = new Uri(option.BaseAddress);
                })
                .AddHttpMessageHandler();

            return builder;
        }

        private static IHttpClientBuilder AddHttpMessageHandler(this IHttpClientBuilder builder)
        {
            builder.ConfigureHttpMessageHandlerBuilder(cfg =>
            {
                var handlers = cfg.Services.GetServices<DelegatingHandler>();
                foreach (var delegatingHandler in handlers)
                {
                    cfg.AdditionalHandlers.Add(delegatingHandler);
                }
            });
            return builder;
        }
    }

Therefore, I need to have a request forwarding site to help me forward requests to different sites. Naturally thought of Ocelot. Ocelot is an excellent open source gateway project.

The Server in my Blazor project mainly has the following functions:

  • Integrate Ocelot as a gateway to forward requests
  • Integrate Azure ApplicationInsights to record interface request exceptions
  • Invoke the Blazor.Client program

long story short

Here I will not repeat the application of Ocelot, but only introduce its use in Blazor.

Example of integrating Ocelot:

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, builder) =>
                {
                    builder
                        .SetBasePath(hostingContext.HostingEnvironment.ContentRootPath)
                        .AddJsonFile($"/Ocelot/Ocelot.json", true, true)
                        .AddJsonFile($"/Ocelot/ocelot.{hostingContext.HostingEnvironment.EnvironmentName.ToLower()}.json", true, true)
                        .AddEnvironmentVariables();
                })
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>();
                });
    }

When the client calls, specify the BaseAddress of HttpClientFactory as builder.HostEnvironment.BaseAddress (see the above example), add the forwarding node identifier, such as /login, to the request url, and then Ocelot will find the site corresponding to /login according to your configuration file , for request forwarding:

var request = new HttpRequestMessage(HttpMethod.Get, "/login/Auth/UserInfo");

How to make Ocelot not block the middleware pipeline, and enter the next middleware when the forwarding routing path cannot be found

It should be noted that Ocelot usually requires blocking the middleware pipeline, so it will cause the blazor page navigation to fail, that is, normal page jumps will also be forwarded as requests . Therefore, we need to modify the Ocelot middleware. When it cannot find the forwarding route, it will automatically enter the next middleware.

Examples are as follows:

        public static IApplicationBuilder UseOcelotWhenRouteMatch(this IApplicationBuilder app)
        {
            app.MapWhen(context =>
            {
                var internalConfigurationResponse = context.RequestServices.GetRequiredService<IInternalConfigurationRepository>().Get();
                if (internalConfigurationResponse.IsError || internalConfigurationResponse.Data.Routes.Count == 0)
                {
                    return false;
                }

                var internalConfiguration = internalConfigurationResponse.Data;
                var downstreamRouteFinder = context.RequestServices.GetRequiredService<IDownstreamRouteProviderFactory>().Get(internalConfiguration);

                var response = downstreamRouteFinder.Get(context.Request.Path, context.Request.QueryString.ToString(),
                    context.Request.Method, internalConfiguration, context.Request.Host.ToString());
                return !response.IsError && !string.IsNullOrEmpty(response.Data?.Route?.DownstreamRoute?.FirstOrDefault()?.DownstreamScheme);
            }, appBuilder => appBuilder.UseOcelot().Wait());

            return app;
        }

Startup.cs

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseWebAssemblyDebugging();
            }

            app.UseBlazorFrameworkFiles();
            app.UseStaticFiles();

            app.UseRouting();

            app.UseOcelotWhenRouteMatch();

            app.UseEndpoints(builder =>
            {
                builder.MapFallbackToFile("index.html");
            });
        }

Guess you like

Origin blog.csdn.net/qq_40404477/article/details/109347733