ASP.NET Core 中的静态文件Static files in ASP.NET Core

作者:Rick AndersonScott AddieBy Rick Anderson and Scott Addie

静态文件(如 HTML、CSS、图像和 JavaScript)是 ASP.NET Core 应用直接提供给客户端的资产。Static files, such as HTML, CSS, images, and JavaScript, are assets an ASP.NET Core app serves directly to clients. 需要进行一些配置才能提供这些文件。Some configuration is required to enable serving of these files.

查看或下载示例代码如何下载View or download sample code (how to download)

提供静态文件Serve static files

静态文件存储在项目的 Web 根目录中。Static files are stored within your project's web root directory. 默认目录是 <content_root>/wwwroot,但可通过 UseWebRoot 方法更改目录。The default directory is <content_root>/wwwroot, but it can be changed via the UseWebRoot method. 有关详细信息,请参阅内容根目录Web 根目录See Content root and Web root for more information.

应用的 Web 主机必须识别内容根目录。The app's web host must be made aware of the content root directory.

采用 WebHost.CreateDefaultBuilder 方法可将内容根目录设置为当前目录:The WebHost.CreateDefaultBuilder method sets the content root to the current directory:

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

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

调用 Program.Main 中的 UseContentRoot 将内容根目录设为当前目录:Set the content root to the current directory by invoking UseContentRoot inside of Program.Main:

public class Program
{
    public static void Main(string[] args)
    {
        var host = new WebHostBuilder()
            .UseKestrel()
            .UseContentRoot(Directory.GetCurrentDirectory())
            .UseIISIntegration()
            .UseStartup<Startup>()
            .UseApplicationInsights()
            .Build();

        host.Run();
    }        
}

可通过 Web 根目录的相关路径访问静态文件。Static files are accessible via a path relative to the web root. 例如,Web 应用程序项目模板包含 wwwroot 文件夹中的多个文件夹:For example, the Web Application project template contains several folders within the wwwroot folder:

  • wwwrootwwwroot
    • csscss
    • imagesimages
    • jsjs

用于访问 images 子文件夹中的文件的 URI 格式为 http://<server_address>/images/<image_file_name>。The URI format to access a file in the images subfolder is http://<server_address>/images/<image_file_name>. 例如,http://localhost:9189/images/banner3.svgFor example, http://localhost:9189/images/banner3.svg.

如果以 .NET Framework 为目标,请将 Microsoft.AspNetCore.StaticFiles 包添加到项目。If targeting .NET Framework, add the Microsoft.AspNetCore.StaticFiles package to your project. 如果以 .NET Core 为目标,Microsoft.AspNetCore.App 元包将包括此包。If targeting .NET Core, the Microsoft.AspNetCore.App metapackage includes this package.

如果以 .NET Framework 为目标,请将 Microsoft.AspNetCore.StaticFiles 包添加到项目。If targeting .NET Framework, add the Microsoft.AspNetCore.StaticFiles package to your project. 如果以 .NET Core 为目标,请将 Microsoft.AspNetCore.All 元包加入此包。If targeting .NET Core, the Microsoft.AspNetCore.All metapackage includes this package.

Microsoft.AspNetCore.StaticFiles 包添加到项目。Add the Microsoft.AspNetCore.StaticFiles package to your project.

配置提供静态文件的中间件Configure the middleware which enables the serving of static files.

提供 Web 根目录内的文件Serve files inside of web root

调用 Startup.Configure 中的 UseStaticFiles 方法:Invoke the UseStaticFiles method within Startup.Configure:

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

无参数 UseStaticFiles 方法重载将 Web 根目录中的文件标记为可用。The parameterless UseStaticFiles method overload marks the files in web root as servable. 以下标记引用 wwwroot/images/banner1.svg:The following markup references wwwroot/images/banner1.svg:

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

在上面的代码中,波形符 ~/ 指向 Web 根目录。In the preceding code, the tilde character ~/ points to webroot. 有关详细信息,请参阅 Web 根目录For more information, see Web root.

提供 Web 根目录外的文件Serve files outside of web root

考虑一个目录层次结构,其中要提供的静态文件位于 Web 根目录之外:Consider a directory hierarchy in which the static files to be served reside outside of the web root:

  • wwwrootwwwroot
    • csscss
    • imagesimages
    • jsjs
  • MyStaticFilesMyStaticFiles
    • imagesimages
      • banner1.svgbanner1.svg

按如下方式配置静态文件中间件后,请求可访问 banner1.svg 文件:A request can access the banner1.svg file by configuring the Static File Middleware as follows:

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 段公开。In the preceding code, the MyStaticFiles directory hierarchy is exposed publicly via the StaticFiles URI segment. 请求 http://<server_address>/StaticFiles/images/banner1.svg 提供 banner1.svg 文件。A request to http://<server_address>/StaticFiles/images/banner1.svg serves the banner1.svg file.

以下标记引用 MyStaticFiles/images/banner1.svg:The following markup references MyStaticFiles/images/banner1.svg:

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

设置 HTTP 响应标头Set HTTP response headers

StaticFileOptions 对象可用于设置 HTTP 响应标头。A StaticFileOptions object can be used to set HTTP response headers. 除配置从 Web 根目录提供静态文件外,以下代码还设置 Cache-Control 标头:In addition to configuring static file serving from the web root, the following code sets the Cache-Control header:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    var cachePeriod = env.IsDevelopment() ? "600" : "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}");
        }
    });
}

HeaderDictionaryExtensions.Append 方法存在于 Microsoft.AspNetCore.Http 包中。The HeaderDictionaryExtensions.Append method exists in the Microsoft.AspNetCore.Http package.

在开发环境中可公开缓存这些文件 10 分钟(600 秒):The files have been made publicly cacheable for 10 minutes (600 seconds) in the Development environment:

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

静态文件授权Static file authorization

静态文件中间件不提供授权检查。The Static File Middleware doesn't provide authorization checks. 可公开访问由静态文件中间件提供的任何文件,包括 wwwroot 下的文件。Any files served by it, including those under wwwroot, are publicly accessible. 根据授权提供文件:To serve files based on authorization:

  • 将文件存储在 wwwroot 和静态文件中间件可访问的任何目录之外。Store them outside of wwwroot and any directory accessible to the Static File Middleware.

  • 通过有授权的操作方法提供文件。Serve them via an action method to which authorization is applied. 返回 FileResult 对象:Return a FileResult object:

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

启用目录浏览Enable directory browsing

通过目录浏览,Web 应用的用户可查看目录列表和指定目录中的文件。Directory browsing allows users of your web app to see a directory listing and files within a specified directory. 出于安全考虑,目录浏览默认处于禁用状态(请参阅注意事项)。Directory browsing is disabled by default for security reasons (see Considerations). 调用 Startup.Configure 中的 UseDirectoryBrowser 方法来启用目录浏览:Enable directory browsing by invoking the UseDirectoryBrowser method in Startup.Configure:

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 方法来添加所需服务:Add required services by invoking the AddDirectoryBrowser method from Startup.ConfigureServices:

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

上述代码允许使用 URL http://<server_address>/MyImages 浏览 wwwroot/images 文件夹的目录,并链接到每个文件和文件夹:The preceding code allows directory browsing of the wwwroot/images folder using the URL http://<server_address>/MyImages, with links to each file and folder:

目录浏览

有关启用浏览时的安全风险,请参阅注意事项See Considerations on the security risks when enabling browsing.

请注意以下示例中的两个 UseStaticFiles 调用。Note the two UseStaticFiles calls in the following example. 第一个调用提供 wwwroot 文件夹中的静态文件。The first call enables the serving of static files in the wwwroot folder. 第二个调用使用 URL http://<server_address>/MyImages 浏览 wwwroot/images 文件夹的目录:The second call enables directory browsing of the wwwroot/images folder using the URL http://<server_address>/MyImages:

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"
    });
}

提供默认文档Serve a default document

设置默认主页为访问者访问网站时提供了逻辑起点。Setting a default home page provides visitors a logical starting point when visiting your site. 若要在用户不完全限定 URI 的情况下提供默认页面,请调用 Startup.Configure 中的 UseDefaultFiles 方法:To serve a default page without the user fully qualifying the URI, call the UseDefaultFiles method from Startup.Configure:

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

重要

要提供默认文件,必须在 UseStaticFiles 前调用 UseDefaultFilesUseDefaultFiles must be called before UseStaticFiles to serve the default file. UseDefaultFiles 实际上用于重写 URL,不提供文件。UseDefaultFiles is a URL rewriter that doesn't actually serve the file. 通过 UseStaticFiles 启用静态文件中间件来提供文件。Enable Static File Middleware via UseStaticFiles to serve the file.

使用 UseDefaultFiles 请求文件夹搜索:With UseDefaultFiles, requests to a folder search for:

  • default.htmdefault.htm
  • default.htmldefault.html
  • index.htmindex.htm
  • index.htmlindex.html

将请求视为完全限定 URI,提供在列表中找到的第一个文件。The first file found from the list is served as though the request were the fully qualified URI. 浏览器 URL 继续反映请求的 URI。The browser URL continues to reflect the URI requested.

以下代码将默认文件名更改为 mydefault.html:The following code changes the default file name to 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();
}

UseFileServerUseFileServer

UseFileServer 结合了 UseStaticFilesUseDefaultFilesUseDirectoryBrowser 的功能。UseFileServer combines the functionality of UseStaticFiles, UseDefaultFiles, and UseDirectoryBrowser.

以下代码提供静态文件和默认文件。The following code enables the serving of static files and the default file. 未启用目录浏览。Directory browsing isn't enabled.

app.UseFileServer();

以下代码通过启用目录浏览基于无参数重载进行构建:The following code builds upon the parameterless overload by enabling directory browsing:

app.UseFileServer(enableDirectoryBrowsing: true);

考虑以下目录层次结构:Consider the following directory hierarchy:

  • wwwrootwwwroot
    • csscss
    • imagesimages
    • jsjs
  • MyStaticFilesMyStaticFiles
    • imagesimages
      • banner1.svgbanner1.svg
    • default.htmldefault.html

以下代码启用静态文件、默认文件和及 MyStaticFiles 的目录浏览:The following code enables static files, default files, and directory browsing of 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 时必须调用 AddDirectoryBrowserAddDirectoryBrowser must be called when the EnableDirectoryBrowsing property value is true:

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

使用文件层次结构和前面的代码,URL 解析如下:Using the file hierarchy and preceding code, URLs resolve as follows:

URIURI 响应Response
http://<server_address>/StaticFiles/images/banner1.svghttp://<server_address>/StaticFiles/images/banner1.svg MyStaticFiles/images/banner1.svgMyStaticFiles/images/banner1.svg
http://<server_address>/StaticFileshttp://<server_address>/StaticFiles MyStaticFiles/default.htmlMyStaticFiles/default.html

如果 MyStaticFiles 目录中不存在默认命名文件,则 http://<server_address>/StaticFiles 返回包含可单击链接的目录列表:If no default-named file exists in the MyStaticFiles directory, http://<server_address>/StaticFiles returns the directory listing with clickable links:

静态文件列表

备注

UseDefaultFilesUseDirectoryBrowser 执行从 http://{SERVER ADDRESS}/StaticFiles(不带尾部斜杠)到 http://{SERVER ADDRESS}/StaticFiles/(带尾部斜杠)的客户端重定向。UseDefaultFiles and UseDirectoryBrowser perform a client-side redirect from http://{SERVER ADDRESS}/StaticFiles (without a trailing slash) to http://{SERVER ADDRESS}/StaticFiles/ (with a trailing slash). 如果没有尾部斜杠,StaticFiles 目录中的相对 URL 无效。Relative URLs within the StaticFiles directory are invalid without a trailing slash.

FileExtensionContentTypeProviderFileExtensionContentTypeProvider

FileExtensionContentTypeProvider 类包含 Mappings 属性,用作文件扩展名到 MIME 内容类型的映射。The FileExtensionContentTypeProvider class contains a Mappings property serving as a mapping of file extensions to MIME content types. 在以下示例中,多个文件扩展名注册到了已知的 MIME 类型。In the following sample, several file extensions are registered to known MIME types. 替换了 .rtf 扩展名,删除了 .mp4。The .rtf extension is replaced, and .mp4 is removed.

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 内容类型See MIME content types.

非标准内容类型Non-standard content types

静态文件中间件可理解近 400 种已知文件内容类型。Static File Middleware understands almost 400 known file content types. 如果用户请求文件类型未知的文件,则静态文件中间件将请求传递给管道中的下一个中间件。If the user requests a file with an unknown file type, Static File Middleware passes the request to the next middleware in the pipeline. 如果没有中间件处理请求,则返回“404 未找到”响应。If no middleware handles the request, a 404 Not Found response is returned. 如果启用了目录浏览,则在目录列表中会显示该文件的链接。If directory browsing is enabled, a link to the file is displayed in a directory listing.

以下代码提供未知类型,并以图像形式呈现未知文件:The following code enables serving unknown types and renders the unknown file as an image:

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

使用前面的代码,请求的文件含未知内容类型时,以图像形式返回请求。With the preceding code, a request for a file with an unknown content type is returned as an image.

警告

启用 ServeUnknownFileTypes 存在安全风险。Enabling ServeUnknownFileTypes is a security risk. 它默认处于禁用状态,不建议使用。It's disabled by default, and its use is discouraged. FileExtensionContentTypeProvider 提供了更安全的替代方法来提供含非标准扩展名的文件。FileExtensionContentTypeProvider provides a safer alternative to serving files with non-standard extensions.

注意事项Considerations

警告

UseDirectoryBrowserUseStaticFiles 可能会泄漏机密。UseDirectoryBrowser and UseStaticFiles can leak secrets. 强烈建议在生产中禁用目录浏览。Disabling directory browsing in production is highly recommended. 请仔细查看 UseStaticFilesUseDirectoryBrowser 启用了哪些目录。Carefully review which directories are enabled via UseStaticFiles or UseDirectoryBrowser. 整个目录及其子目录均可公开访问。The entire directory and its sub-directories become publicly accessible. 将适合公开的文件存储在专用目录中,如 <content_root>/wwwroot。Store files suitable for serving to the public in a dedicated directory, such as <content_root>/wwwroot. 将这些文件与 MVC 视图、Razor 页面(仅限 2.x)和配置文件等分开Separate these files from MVC views, Razor Pages (2.x only), configuration files, etc.

  • 使用 UseDirectoryBrowserUseStaticFiles 公开的内容的 URL 受大小写和基础文件系统字符限制的影响。The URLs for content exposed with UseDirectoryBrowser and UseStaticFiles are subject to the case sensitivity and character restrictions of the underlying file system. 例如,Windows 不区分大小写 — macOS 和 Linux 却要区分。For example, Windows is case insensitive—macOS and Linux aren't.

  • 托管于 IIS 中的 ASP.NET Core 应用使用 ASP.NET Core 模块将所有请求转发到应用,包括静态文件请求。ASP.NET Core apps hosted in IIS use the ASP.NET Core Module to forward all requests to the app, including static file requests. 未使用 IIS 静态文件处理程序。The IIS static file handler isn't used. 在模块处理请求前,处理程序没有机会处理请求。It has no chance to handle requests before they're handled by the module.

  • 在 IIS Manager 中完成以下步骤,删除服务器或网站级别的 IIS 静态文件处理程序:Complete the following steps in IIS Manager to remove the IIS static file handler at the server or website level:

    1. 转到“模块”功能。Navigate to the Modules feature.
    2. 在列表中选择 StaticFileModule。Select StaticFileModule in the list.
    3. 单击“操作”侧栏中的“删除”。Click Remove in the Actions sidebar.

警告

如果启用了 IIS 静态文件处理程序且 ASP.NET Core 模块配置不正确,则会提供静态文件。If the IIS static file handler is enabled and the ASP.NET Core Module is configured incorrectly, static files are served. 例如,如果未部署 web.config 文件,则会发生这种情况。This happens, for example, if the web.config file isn't deployed.

  • 将代码文件(包括 .cs 和 .cshtml )放在应用项目的 Web 根目录之外。Place code files (including .cs and .cshtml) outside of the app project's web root. 这样就在应用的客户端内容和基于服务器的代码间创建了逻辑分隔。A logical separation is therefore created between the app's client-side content and server-based code. 可以防止服务器端代码泄漏。This prevents server-side code from being leaked.

其他资源Additional resources