dotnet core UseStaticFiles 索引回退

dotnet core UseStaticFiles index fallback

我的 Startup.cs 中有这个 Configure 方法。 它做了 3 件事 :

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

         app.UseHttpsRedirection();

         // Defaults to index.html
         var defaultFilesOptions = new DefaultFilesOptions();
         defaultFilesOptions.DefaultFileNames.Clear();
         defaultFilesOptions.DefaultFileNames.Add("index.html");
         app.UseDefaultFiles(defaultFilesOptions);

         var staticFileOptions = new StaticFileOptions
         {
            OnPrepareResponse = ctx =>
            {
               // Add CSP for index.html
               if (ctx.File.Name == "index.html")
               {
                  ctx.Context.Response.Headers.Append(
                     "Content-Security-Policy", "default-src 'self'" // etc
                  );
               }
            }
         };

         app.UseStaticFiles(staticFileOptions); // wwwroot

         app.UseRouting();

         app.UseEndpoints(endpoints =>
         {
            // Settings.json endpoint
            endpoints.MapGet("/settings.json", async context =>
            {
               string json = $@"
                {{
                   ""myConfig"": ""{_configuration["myParameter"]}""
                }}";
               await context.Response.WriteAsync(json);
            });
         });
      }
   }

wwwroot下的文件其实是一个vue.js带路由的app。对于所有不存在的请求,我需要 return index.html,以便客户端路由控制页面。

目前它 return 是一个 404 并且不会传入 OnPrepareResponse 钩子。

如何为路由器配置索引回退以在历史模式下工作? 我认为它可以通过 web.config 中的配置来实现,但我更愿意在 Startup.js 中进行配置,所以它们都在同一个地方。

我最终编写了一个执行索引回退的文件提供程序。如果找不到文件,它封装了一个PhysicalFileProvider和return index.html。在我的例子中,条件基于文件夹 css、img 或 js.

是这样实现的:

using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Primitives;
using System.Linq;

public class IndexFallbackFileProvider : IFileProvider
{
   private readonly PhysicalFileProvider _innerProvider;

   public IndexFallbackFileProvider(PhysicalFileProvider physicalFileProvider)
   {
      _innerProvider = physicalFileProvider;    
   }

   public IDirectoryContents GetDirectoryContents(string subpath)
   {
      return _innerProvider.GetDirectoryContents(subpath);
   }

   public IFileInfo GetFileInfo(string subpath)
   {
      var fileInfo = _innerProvider.GetFileInfo(subpath);
      if(!fileInfo.Exists && MustFallbackToIndex(subpath))
      {
         if(!_staticFilesFolders.Any(f => subpath.Contains(f)))
         {
            fileInfo = _innerProvider.GetFileInfo("/index.html");
         }         
      }

      return fileInfo;
   }

   // Plain 404 are OK for css, img, js.
   private static string[] _staticFilesFolders = new string[] { "/css/", "/img/", "/js/" };
   private static bool MustFallbackToIndex(string subpath)
   {
      return !_staticFilesFolders.Any(f => subpath.Contains(f));
   }

   public IChangeToken Watch(string filter)
   {
      return _innerProvider.Watch(filter);
   }
}

然后,在startup.config,我使用了这个供应商。 另外,我必须将 ServeUnknownFileTypes 设置为 true 以响应对 /path/without/extension.

的请求
var physicalFileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "wwwroot"));
var fileProvider = new IndexFallbackFileProvider(physicalFileProvider);

var staticFileOptions = new StaticFileOptions
{
   FileProvider = fileProvider,
   ServeUnknownFileTypes = true
};

app.UseStaticFiles(staticFileOptions);