ASP.NET Core 中的静态文件

作者:Rick AndersonKirk Larkin

默认情况下,静态文件(如 HTML、CSS、图像和 JavaScript)是 ASP.NET Core 应用直接提供给客户端的资产。

查看或下载示例代码如何下载

提供静态文件

静态文件存储在项目的 Web 根目录中。 默认目录为 {content root}/wwwroot,但可通过 UseWebRoot 方法更改目录。 有关详细信息,请参阅内容根目录Web 根目录

采用 CreateDefaultBuilder 方法可将内容根目录设置为当前目录:

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
}

上述代码是使用 Web 应用程序模板创建的。

可通过 Web 根目录的相关路径访问静态文件。 例如,Web 应用程序项目模板包含 wwwroot 文件夹中的多个文件夹:

  • wwwroot
    • css
    • js
    • lib

请考虑创建 wwwroot/images 文件夹,并添加 wwwroot/images/MyImage 文件。 用于访问 images 文件夹中的文件的 URI 格式为 https://<hostname>/images/<image_file_name>。 例如,https://localhost:5001/images/MyImage.jpg

在 Web 根目录中提供文件

默认 Web 应用模板在 Startup.Configure 中调用 UseStaticFiles 方法,这将允许提供静态文件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

无参数 UseStaticFiles 方法重载将 Web 根目录中的文件标记为可用。 以下标记引用 wwwroot/images/MyImage.jpg:

<img src="~/images/MyImage.jpg" class="img" alt="My image" />

在上面的代码中,波形符 ~/ 指向 Web 根目录

提供 Web 根目录外的文件

考虑一个目录层次结构,其中要提供的静态文件位于 Web 根目录之外:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • red-rose.jpg

按如下方式配置静态文件中间件后,请求可访问 red-rose.jpg 文件:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

在前面的代码中,MyStaticFiles 目录层次结构通过 StaticFiles URI 段公开 。 对 https://<hostname>/StaticFiles/images/red-rose.jpg 的请求将提供 red-rose.jpg 文件。

以下标记引用 MyStaticFiles/images/red-rose.jpg:

<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />

设置 HTTP 响应标头

StaticFileOptions 对象可用于设置 HTTP 响应标头。 除配置从 Web 根目录提供静态文件外,以下代码还设置 Cache-Control 标头:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    const string cacheMaxAge = "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append(
                 "Cache-Control", $"public, max-age={cacheMaxAge}");
        }
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

静态文件可在 600 秒内公开缓存:

已添加显示 Cache-Control 标头的响应头

静态文件授权

ASP.NET Core 模板在调用 UseAuthorization 之前调用 UseStaticFiles。 大多数应用都遵循此模式。 如果在授权中间件之前调用静态文件中间件:

  • 不会对静态文件执行任何授权检查。
  • 由静态文件中间件提供的静态文件(例如 wwwroot 下的文件)可公开访问。

根据授权提供静态文件:

  • 将它们存储在 wwwroot 之外。
  • 调用 UseAuthorization 之后调用 UseStaticFiles,以指定路径。
  • 设置回退授权策略
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // wwwroot css, JavaScript, and images don't require authentication.
    app.UseStaticFiles();   

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
                     Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();

        services.AddAuthorization(options =>
        {
            options.FallbackPolicy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
        });
    }

    // Remaining code ommitted for brevity.

在前面的代码中,回退授权策略要求所有用户进行身份验证。 用于指定其自己的授权要求的终结点(如控制器、Razor Pages 等)不使用回退授权策略。 例如,具有 [AllowAnonymous][Authorize(PolicyName="MyPolicy")] 的 Razor Pages、控制器或操作方法使用应用的授权属性,而不是回退授权策略。

RequireAuthenticatedUserDenyAnonymousAuthorizationRequirement 添加到当前实例,这将强制对当前用户进行身份验证。

wwwroot 下的静态资产是可公开访问的,因为在 UseAuthentication 之前会调用默认静态文件中间件 (app.UseStaticFiles();)。 MyStaticFiles 文件夹中的静态资产需要身份验证。 示例代码对此进行了演示。

还有一种根据授权提供文件的方法是:

  • 将文件存储在 wwwroot 和静态文件中间件可访问的任何目录之外。
  • 通过应用授权的操作方法为其提供服务,并返回 FileResult 对象:
[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

目录浏览

目录浏览允许在指定目录中列出目录。

出于安全考虑,目录浏览默认处于禁用状态。 有关详细信息,请参阅静态文件的安全注意事项

通过以下方式启用目录浏览:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

上述代码允许使用 URL https://<hostname>/MyImages 浏览 wwwroot/images 文件夹的目录,并链接到每个文件和文件夹:

目录浏览

提供默认文档

设置默认页面为访问者提供网站的起点。 若要从 wwwroot 提供默认文件,而不要求请求 URL 包含文件名,请调用 UseDefaultFiles 方法:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseDefaultFiles();
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

要提供默认文件,必须在 UseStaticFiles 前调用 UseDefaultFilesUseDefaultFiles 是不提供文件的 URL 重写工具。

使用 UseDefaultFiles 请求对 wwwroot 中的文件夹搜索:

  • default.htm
  • default.html
  • index.htm
  • index.html

如同请求包含了文件名一样,提供从列表中找到的第一个文件。 浏览器 URL 继续反映请求的 URI。

以下代码将默认文件名更改为 mydefault.html:

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();

以下代码通过上述代码演示了 Startup.Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    var options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

默认文档的 UseFileServer

UseFileServer 结合了 UseStaticFilesUseDefaultFilesUseDirectoryBrowser(可选)的功能。

调用 app.UseFileServer 以提供静态文件和默认文件。 未启用目录浏览。 以下代码通过 UseFileServer 演示了 Startup.Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer();

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

以下代码提供静态文件、默认文件和目录浏览:

app.UseFileServer(enableDirectoryBrowsing: true);

以下代码通过上述代码演示了 Startup.Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseFileServer(enableDirectoryBrowsing: true);

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

考虑以下目录层次结构:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • MyImage.jpg
    • default.html

以下代码提供静态文件、默认文件和 MyStaticFiles 的目录浏览:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllersWithViews();
    services.AddDirectoryBrowser();
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(); // For the wwwroot folder.

    // using Microsoft.Extensions.FileProviders;
    // using System.IO;
    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.ContentRootPath, "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

必须在 EnableDirectoryBrowsing 属性值为 true 时调用 AddDirectoryBrowser

使用文件层次结构和前面的代码,URL 解析如下:

URI 响应
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.html

如果 MyStaticFiles 目录中不存在默认命名文件,则 https://<hostname>/StaticFiles 返回包含可单击链接的目录列表:

静态文件列表

UseDefaultFilesUseDirectoryBrowser 执行从不带尾部 / 的目标 URI 到带尾部 / 的目标 URI 的客户端重定向。 例如,从 https://<hostname>/StaticFileshttps://<hostname>/StaticFiles/。 如果没有尾部斜杠 (/),StaticFiles 目录中的相对 URL 无效。

FileExtensionContentTypeProvider

FileExtensionContentTypeProvider 类包含 Mappings 属性,用作文件扩展名到 MIME 内容类型的映射。 在以下示例中,多个文件扩展名映射到了已知的 MIME 类型。 替换了 .rtf 扩展名,删除了 .mp4 :

// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/MyImages"
});

以下代码通过上述代码演示了 Startup.Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    // using Microsoft.AspNetCore.StaticFiles;
    // using Microsoft.Extensions.FileProviders;
    // using System.IO;

    // Set up custom content types - associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".myapp"] = "application/x-msdownload";
    provider.Mappings[".htm3"] = "text/html";
    provider.Mappings[".image"] = "image/png";
    // Replace an existing mapping
    provider.Mappings[".rtf"] = "application/x-msdownload";
    // Remove MP4 videos.
    provider.Mappings.Remove(".mp4");

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(env.WebRootPath, "images")),
        RequestPath = "/MyImages"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

请参阅 MIME 内容类型

非标准内容类型

静态文件中间件可理解近 400 种已知文件内容类型。 如果用户请求文件类型未知的文件,则静态文件中间件将请求传递给管道中的下一个中间件。 如果没有中间件处理请求,则返回“404 未找到”响应。 如果启用了目录浏览,则在目录列表中会显示该文件的链接。

以下代码提供未知类型,并以图像形式呈现未知文件:

app.UseStaticFiles(new StaticFileOptions
{
    ServeUnknownFileTypes = true,
    DefaultContentType = "image/png"
});

以下代码通过上述代码演示了 Startup.Configure

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }

    app.UseHttpsRedirection();

    app.UseStaticFiles(new StaticFileOptions
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapDefaultControllerRoute();
    });
}

使用前面的代码,请求的文件含未知内容类型时,以图像形式返回请求。

警告

启用 ServeUnknownFileTypes 会形成安全隐患。 它默认处于禁用状态,不建议使用。 FileExtensionContentTypeProvider 提供了更安全的替代方法来提供含非标准扩展名的文件。

从多个位置提供文件

UseStaticFilesUseFileServer 默认为指向 wwwroot 的文件提供程序。 可使用其他文件提供程序提供 UseStaticFilesUseFileServer 的其他实例,从多个位置提供文件。 有关详细信息,请参阅此 GitHub 问题

静态文件的安全注意事项

警告

UseDirectoryBrowserUseStaticFiles 可能会泄漏机密。 强烈建议在生产中禁用目录浏览。 请仔细查看 UseStaticFilesUseDirectoryBrowser 启用了哪些目录。 整个目录及其子目录均可公开访问。 将适合公开的文件存储在专用目录中,如 <content_root>/wwwroot。 将这些文件与 MVC 视图、Razor Pages 和配置文件等分开。

  • 使用 UseDirectoryBrowserUseStaticFiles 公开的内容的 URL 受大小写和基础文件系统字符限制的影响。 例如,Windows 不区分大小写,但 macOS 和 Linux 区分大小写。

  • 托管于 IIS 中的 ASP.NET Core 应用使用 ASP.NET Core 模块将所有请求转发到应用,包括静态文件请求。 不使用 IIS 静态文件处理程序,并且没有机会处理请求。

  • 在 IIS Manager 中完成以下步骤,删除服务器或网站级别的 IIS 静态文件处理程序:

    1. 转到“模块”功能。
    2. 在列表中选择 StaticFileModule。
    3. 单击“操作”侧栏中的“删除” 。

警告

如果启用了 IIS 静态文件处理程序且 ASP.NET Core 模块配置不正确,则会提供静态文件。 例如,如果未部署 web.config 文件,则会发生这种情况。

  • 将代码文件(包括 .cs 和 .cshtml)放在应用项目的 Web 根目录之外 。 这样就在应用的客户端内容和基于服务器的代码间创建了逻辑分隔。 可以防止服务器端代码泄漏。

其他资源

作者:Rick AndersonScott Addie

静态文件(如 HTML、CSS、图像和 JavaScript)是 ASP.NET Core 应用直接提供给客户端的资产。 需要进行一些配置才能提供这些文件。

查看或下载示例代码如何下载

提供静态文件

静态文件存储在项目的 Web 根目录中。 默认目录是 {content root}/wwwroot,但可通过 UseWebRoot 方法更改目录。 有关详细信息,请参阅内容根目录Web 根目录

应用的 Web 主机必须识别内容根目录。

采用 WebHost.CreateDefaultBuilder 方法可将内容根目录设置为当前目录:

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

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

可通过 Web 根目录的相关路径访问静态文件。 例如,Web 应用程序项目模板包含 wwwroot 文件夹中的多个文件夹:

  • wwwroot
    • css
    • images
    • js

用于访问 images 子文件夹中的文件的 URI 格式为 http://<server_address>/images/<image_file_name> 。 例如, http://localhost:9189/images/banner3.svg

如果以 .NET Framework 为目标,请将 Microsoft.AspNetCore.StaticFiles 包添加到项目。 如果以 .NET Core 为目标,Microsoft.AspNetCore.App 元包将包括此包。

配置提供静态文件的中间件

提供 Web 根目录内的文件

调用 Startup.Configure 中的 UseStaticFiles 方法:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
}

无参数 UseStaticFiles 方法重载将 Web 根目录中的文件标记为可用。 以下标记引用 wwwroot/images/banner1.svg:

<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />

在上面的代码中,波形符 ~/ 指向 Web 根目录

提供 Web 根目录外的文件

考虑一个目录层次结构,其中要提供的静态文件位于 Web 根目录之外:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • banner1.svg

按如下方式配置静态文件中间件后,请求可访问 banner1.svg 文件:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });
}

在前面的代码中,MyStaticFiles 目录层次结构通过 StaticFiles URI 段公开 。 请求 http://<server_address>/StaticFiles/images/banner1.svg 提供 banner1.svg 文件 。

以下标记引用 MyStaticFiles/images/banner1.svg:

<img src="~/StaticFiles/images/banner1.svg" alt="ASP.NET" class="img-responsive" />

设置 HTTP 响应标头

StaticFileOptions 对象可用于设置 HTTP 响应标头。 除配置从 Web 根目录提供静态文件外,以下代码还设置 Cache-Control 标头:

public void Configure(IApplicationBuilder app)
{
    var cachePeriod =  "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // Requires the following import:
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age={cachePeriod}");
        }
    });
}

若要查看翻译为非英语语言的代码注释,请在 此 GitHub 讨论问题中告诉我们。

HeaderDictionaryExtensions.Append 方法位于 Microsoft.AspNetCore.Http 包中。

在开发环境中可公开缓存这些文件 10 分钟(600 秒):

已添加显示 Cache-Control 标头的响应头

静态文件授权

静态文件中间件不提供授权检查。 可公开访问由静态文件中间件提供的任何文件,包括 wwwroot 下的文件。 根据授权提供文件:

  • 将文件存储在 wwwroot 和静态文件中间件可访问的任何目录之外。

  • 通过有授权的操作方法提供文件。 返回一个 FileResult 对象:

    [Authorize]
    public IActionResult BannerImage()
    {
        var file = Path.Combine(Directory.GetCurrentDirectory(), 
                                "MyStaticFiles", "images", "banner1.svg");
    
        return PhysicalFile(file, "image/svg+xml");
    }
    

启用目录浏览

通过目录浏览,Web 应用的用户可查看目录列表和指定目录中的文件。 出于安全考虑,目录浏览默认处于禁用状态(请参阅注意事项)。 调用 Startup.Configure 中的 UseDirectoryBrowser 方法来启用目录浏览:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });
}

通过从 Startup.ConfigureServices 调用 AddDirectoryBrowser 方法添加所需服务:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDirectoryBrowser();
}

上述代码允许使用 URL http://<server_address>/MyImages 浏览 wwwroot/images 文件夹的目录,并链接到每个文件和文件夹 :

目录浏览

有关启用浏览时的安全风险,请参阅注意事项

请注意以下示例中的两个 UseStaticFiles 调用。 第一个调用提供 wwwroot 文件夹中的静态文件。 第二个调用使用 URL http://<server_address>/MyImages 浏览 wwwroot/images 文件夹的目录 :

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });
}

提供默认文档

设置默认主页为访问者访问网站时提供了逻辑起点。 若要在用户不完全限定 URI 的情况下提供默认页面,请调用 Startup.Configure 中的 UseDefaultFiles 方法:

public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();
    app.UseStaticFiles();
}

重要

要提供默认文件,必须在 UseStaticFiles 前调用 UseDefaultFilesUseDefaultFiles 实际上用于重写 URL,不提供文件。 通过 UseStaticFiles 启用静态文件中间件来提供文件。

使用 UseDefaultFiles 请求文件夹搜索:

  • default.htm
  • default.html
  • index.htm
  • index.html

将请求视为完全限定 URI,提供在列表中找到的第一个文件。 浏览器 URL 继续反映请求的 URI。

以下代码将默认文件名更改为 mydefault.html:

public void Configure(IApplicationBuilder app)
{
    // Serve my app-specific default file, if present.
    DefaultFilesOptions options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();
}

UseFileServer

UseFileServer 结合了 UseStaticFilesUseDefaultFilesUseDirectoryBrowser(可选)的功能。

以下代码提供静态文件和默认文件。 未启用目录浏览。

app.UseFileServer();

以下代码通过启用目录浏览基于无参数重载进行构建:

app.UseFileServer(enableDirectoryBrowsing: true);

考虑以下目录层次结构:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • banner1.svg
    • default.html

以下代码启用静态文件、默认文件和及 MyStaticFiles 的目录浏览:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });
}

EnableDirectoryBrowsing 属性值为 true 时必须调用 AddDirectoryBrowser

public void ConfigureServices(IServiceCollection services)
{
    services.AddDirectoryBrowser();
}

使用文件层次结构和前面的代码,URL 解析如下:

URI 响应
http://<server_address>/StaticFiles/images/banner1.svg MyStaticFiles/images/banner1.svg
http://<server_address>/StaticFiles MyStaticFiles/default.html

如果 MyStaticFiles 目录中不存在默认命名文件,则 http://<server_address>/StaticFiles 返回包含可单击链接的目录列表 :

静态文件列表

备注

UseDefaultFilesUseDirectoryBrowser 执行从 http://{SERVER ADDRESS}/StaticFiles(不带尾部斜杠)到 http://{SERVER ADDRESS}/StaticFiles/(带尾部斜杠)的客户端重定向。 如果没有尾部斜杠,StaticFiles 目录中的相对 URL 无效。

FileExtensionContentTypeProvider

FileExtensionContentTypeProvider 类包含 Mappings 属性,用作文件扩展名到 MIME 内容类型的映射。 在以下示例中,多个文件扩展名注册到了已知的 MIME 类型。 替换了 .rtf 扩展名,删除了 .mp4 。

public void Configure(IApplicationBuilder app)
{
    // Set up custom content types - associating file extension to MIME type
    var provider = new FileExtensionContentTypeProvider();
    // Add new mappings
    provider.Mappings[".myapp"] = "application/x-msdownload";
    provider.Mappings[".htm3"] = "text/html";
    provider.Mappings[".image"] = "image/png";
    // Replace an existing mapping
    provider.Mappings[".rtf"] = "application/x-msdownload";
    // Remove MP4 videos.
    provider.Mappings.Remove(".mp4");

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });
}

请参阅 MIME 内容类型

若要了解如何使用自定义 FileExtensionContentTypeProvider,或者要配置 Blazor Server 应用中的其他 StaticFileOptions,请参阅 ASP.NET Core Blazor 静态文件

非标准内容类型

静态文件中间件可理解近 400 种已知文件内容类型。 如果用户请求文件类型未知的文件,则静态文件中间件将请求传递给管道中的下一个中间件。 如果没有中间件处理请求,则返回“404 未找到”响应。 如果启用了目录浏览,则在目录列表中会显示该文件的链接。

以下代码提供未知类型,并以图像形式呈现未知文件:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(new StaticFileOptions
    {
        ServeUnknownFileTypes = true,
        DefaultContentType = "image/png"
    });
}

使用前面的代码,请求的文件含未知内容类型时,以图像形式返回请求。

警告

启用 ServeUnknownFileTypes 会形成安全隐患。 它默认处于禁用状态,不建议使用。 FileExtensionContentTypeProvider 提供了更安全的替代方法来提供含非标准扩展名的文件。

从多个位置提供文件

UseStaticFilesUseFileServer 默认为指向 wwwroot 的文件提供程序。 可使用其他文件提供程序提供 UseStaticFilesUseFileServer 的其他实例,从多个位置提供文件。 有关详细信息,请参阅此 GitHub 问题

注意事项

警告

UseDirectoryBrowserUseStaticFiles 可能会泄漏机密。 强烈建议在生产中禁用目录浏览。 请仔细查看 UseStaticFilesUseDirectoryBrowser 启用了哪些目录。 整个目录及其子目录均可公开访问。 将适合公开的文件存储在专用目录中,如 <content_root>/wwwroot。 将这些文件与 MVC 视图、Razor 页面(仅限 2.x)和配置文件等分开。

  • 使用 UseDirectoryBrowserUseStaticFiles 公开的内容的 URL 受大小写和基础文件系统字符限制的影响。 例如,Windows 不区分大小写 — macOS 和 Linux 却要区分。

  • 托管于 IIS 中的 ASP.NET Core 应用使用 ASP.NET Core 模块将所有请求转发到应用,包括静态文件请求。 未使用 IIS 静态文件处理程序。 在模块处理请求前,处理程序没有机会处理请求。

  • 在 IIS Manager 中完成以下步骤,删除服务器或网站级别的 IIS 静态文件处理程序:

    1. 转到“模块”功能。
    2. 在列表中选择 StaticFileModule。
    3. 单击“操作”侧栏中的“删除” 。

警告

如果启用了 IIS 静态文件处理程序且 ASP.NET Core 模块配置不正确,则会提供静态文件。 例如,如果未部署 web.config 文件,则会发生这种情况。

  • 将代码文件(包括 .cs 和 .cshtml )放在应用项目的 Web 根目录之外 。 这样就在应用的客户端内容和基于服务器的代码间创建了逻辑分隔。 可以防止服务器端代码泄漏。

其他资源