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

作者:Rick AndersonKirk LarkinBy Rick Anderson and Kirk Larkin

默认情况下,静态文件(如 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 by default.

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

提供静态文件Serve static files

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

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

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 应用程序模板创建的。The preceding code was created with the web app template.

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

  • wwwroot
    • css
    • js
    • lib

请考虑创建 wwwroot/images 文件夹,并添加 wwwroot/images/MyImage 文件。 Consider creating the wwwroot/images folder and adding the wwwroot/images/MyImage.jpg file. 用于访问 images 文件夹中的文件的 URI 格式为 https://<hostname>/images/<image_file_name>The URI format to access a file in the images folder is https://<hostname>/images/<image_file_name>. 例如,https://localhost:5001/images/MyImage.jpgFor example, https://localhost:5001/images/MyImage.jpg

在 Web 根目录中提供文件Serve files in web root

默认 Web 应用模板在 Startup.Configure 中调用 UseStaticFiles 方法,这将允许提供静态文件:The default web app templates call the UseStaticFiles method in Startup.Configure, which enables static files to be served:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

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

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

在上面的代码中,波形符 ~/ 指向 Web 根目录In the preceding code, the tilde character ~/ points to the 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:

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

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

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

在前面的代码中,MyStaticFiles 目录层次结构通过 StaticFiles URI 段公开 。In the preceding code, the MyStaticFiles directory hierarchy is exposed publicly via the StaticFiles URI segment. https://<hostname>/StaticFiles/images/red-rose.jpg 的请求将提供 red-rose.jpg 文件。A request to https://<hostname>/StaticFiles/images/red-rose.jpg serves the red-rose.jpg file.

以下标记引用 MyStaticFiles/images/red-rose.jpg:The following markup references MyStaticFiles/images/red-rose.jpg:

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

设置 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, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
    }
    else
    {
        app.UseExceptionHandler("/Home/Error");
        app.UseHsts();
    }
    app.UseHttpsRedirection();

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

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

静态文件可在 600 秒内公开缓存:Static files are publicly cacheable for 600 seconds:

已添加显示 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.

  • 通过应用授权的操作方法为其提供服务,并返回 FileResult 对象:Serve them via an action method to which authorization is applied and return a FileResult object:

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

目录浏览Directory browsing

目录浏览允许在指定目录中列出目录。Directory browsing allows directory listing within specified directories.

出于安全考虑,目录浏览默认处于禁用状态。Directory browsing is disabled by default for security reasons. 有关详细信息,请参阅注意事项For more information, see Considerations.

通过以下方式启用目录浏览:Enable directory browsing with:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

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

目录浏览

提供默认文档Serve default documents

设置默认页面为访问者提供网站的起点。Setting a default page provides visitors a starting point on a site. 若要在没有完全限定 URI 的情况下提供 wwwroot 的默认页面,请调用 UseDefaultFiles 方法:To serve a default page from wwwroot without a fully qualified URI, call the UseDefaultFiles method:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=None}/{action=Index}/{id?}");
    });
}

要提供默认文件,必须在 UseStaticFiles 前调用 UseDefaultFilesUseDefaultFiles must be called before UseStaticFiles to serve the default file. UseDefaultFiles 是不提供文件的 URL 重写工具。UseDefaultFiles is a URL rewriter that doesn't serve the file.

使用 UseDefaultFiles 请求对 wwwroot 中的文件夹搜索:With UseDefaultFiles, requests to a folder in wwwroot 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:

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

以下代码通过上述代码演示了 Startup.ConfigureThe following code shows Startup.Configure with the preceding code:

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

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

    app.UseRouting();

    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=None}/{action=Index}/{id?}");
    });
}

默认文档的 UseFileServerUseFileServer for default documents

UseFileServer 结合了 UseStaticFilesUseDefaultFilesUseDirectoryBrowser(可选)的功能。UseFileServer combines the functionality of UseStaticFiles, UseDefaultFiles, and optionally UseDirectoryBrowser.

调用 app.UseFileServer 以提供静态文件和默认文件。Call app.UseFileServer to enable the serving of static files and the default file. 未启用目录浏览。Directory browsing isn't enabled. 以下代码通过 UseFileServer 演示了 Startup.ConfigureThe following code shows Startup.Configure with UseFileServer:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=None}/{action=Index}/{id?}");
    });
}

以下代码提供静态文件、默认文件和目录浏览:The following code enables the serving of static files, the default file, and directory browsing:

app.UseFileServer(enableDirectoryBrowsing: true);

以下代码通过上述代码演示了 Startup.ConfigureThe following code shows Startup.Configure with the preceding code:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=None}/{action=Index}/{id?}");
    });
}

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

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

以下代码提供静态文件、默认文件和 MyStaticFiles 的目录浏览:The following code enables the serving of static files, the default file, and directory browsing of 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.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

必须在 EnableDirectoryBrowsing 属性值为 true 时调用 AddDirectoryBrowserAddDirectoryBrowser must be called when the EnableDirectoryBrowsing property value is true.

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

URIURI 响应Response
https://<hostname>/StaticFiles/images/MyImage.jpg MyStaticFiles/images/MyImage.jpgMyStaticFiles/images/MyImage.jpg
https://<hostname>/StaticFiles MyStaticFiles/default.htmlMyStaticFiles/default.html

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

静态文件列表

UseDefaultFilesUseDirectoryBrowser 执行从不带尾部 / 的目标 URI 到带尾部 / 的目标 URI 的客户端重定向。UseDefaultFiles and UseDirectoryBrowser perform a client-side redirect from the target URI without a trailing / to the target URI with a trailing /. 例如,从 https://<hostname>/StaticFileshttps://<hostname>/StaticFiles/For example, from https://<hostname>/StaticFiles to https://<hostname>/StaticFiles/. 如果没有尾部斜杠 (/),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 that serves as a mapping of file extensions to MIME content types. 在以下示例中,多个文件扩展名映射到了已知的 MIME 类型。In the following sample, several file extensions are mapped to known MIME types. 替换了 .rtf 扩展名,删除了 .mp4 :The .rtf extension is replaced, and .mp4 is removed:

//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.ConfigureThe following code shows Startup.Configure with the preceding code:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

请参阅 MIME 内容类型See MIME content types.

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

静态文件中间件可理解近 400 种已知文件内容类型。The Static File Middleware understands almost 400 known file content types. 如果用户请求文件类型未知的文件,则静态文件中间件将请求传递给管道中的下一个中间件。If the user requests a file with an unknown file type, the 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:

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

以下代码通过上述代码演示了 Startup.ConfigureThe following code shows Startup.Configure with the preceding code:

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.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

使用前面的代码,请求的文件含未知内容类型时,以图像形式返回请求。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.

从多个位置提供文件Serve files from multiple locations

UseStaticFilesUseFileServer 默认为指向 wwwroot 的文件提供程序。UseStaticFiles and UseFileServer default to the file provider pointing at wwwroot. 可使用其他文件提供程序提供 UseStaticFilesUseFileServer 的其他实例,从多个位置提供文件。Additional instances of UseStaticFiles and UseFileServer can be provided with other file providers to serve files from other locations. 有关详细信息,请参阅此 GitHub 问题For more information, see this GitHub issue.

静态文件的安全注意事项Security considerations for static files

警告

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>/wwwrootStore files suitable for serving to the public in a dedicated directory, such as <content_root>/wwwroot. 将这些文件与 MVC 视图、Razor Pages 和配置文件等分开。Separate these files from MVC views, Razor Pages, 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, but 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 and has no chance to handle requests.

  • 在 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

作者: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 the 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>();
}

可通过 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:

  • wwwroot
    • css
    • images
    • js

用于访问 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 the project. 如果以 .NET Core 为目标,Microsoft.AspNetCore.App 元包将包括此包。If targeting .NET Core, the Microsoft.AspNetCore.App metapackage includes this package.

配置提供静态文件的中间件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 the 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:

  • wwwroot
    • css
    • images
    • js
  • MyStaticFiles
    • images
      • banner1.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)
{
    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 讨论问题中告诉我们。If you would like to see code comments translated to languages other than English, let us know in this GitHub discussion issue.

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 optionally 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.

从多个位置提供文件Serve files from multiple locations

UseStaticFilesUseFileServer 默认为指向 wwwroot 的文件提供程序。UseStaticFiles and UseFileServer defaults to the file provider pointing at wwwroot. 可使用其他文件提供程序提供 UseStaticFilesUseFileServer 的其他实例,从多个位置提供文件。You can provide additional instances of UseStaticFiles and UseFileServer with other file providers to serve files from other locations. 有关详细信息,请参阅此 GitHub 问题For more information, see this GitHub issue.

注意事项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