Note
此版本不是本文的最新版本。 对于当前版本,请参阅本文的 .NET 9 版本。
Warning
此版本的 ASP.NET Core 不再受支持。 有关详细信息,请参阅 .NET 和 .NET Core 支持策略。 对于当前版本,请参阅本文的 .NET 9 版本。
Important
此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。
对于当前版本,请参阅本文的 .NET 9 版本。
静态文件(也称为静态资产)是未动态生成的 ASP.NET 核心应用的文件。 相反,它们会根据请求直接提供给客户端,例如 HTML、CSS、图像和 JavaScript 文件。
有关添加或取代本文中指导的 Blazor 静态文件指导,请参阅 ASP.NET Core Blazor 静态文件。
若要在 ASP.NET Core 中启用静态文件处理,请调用 MapStaticAssets。
默认情况下,静态文件存储在项目的 Web 根 目录中。 默认目录是 {CONTENT ROOT}/wwwroot,其中 {CONTENT ROOT} 占位符是应用的 内容根目录。 只有 wwwroot 文件夹中的文件可寻址,因此无需担心其余代码。
只有具有特定文件扩展名并映射到受支持媒体类型的文件,才能作为静态 Web 资产。
在构建时发现静态 Web 资产,并通过内容指纹进行优化,以防止重复使用旧文件。 资产也会 压缩 ,以减少资产交付时间。
在运行时,所发现的静态 Web 资源将作为终结点进行公开,并应用了 HTTP 标头,例如 缓存头 和内容类型头。 在文件更改或浏览器清除缓存之前,资产只提供一次。 设置ETag、Last-Modified和Content-Type标头。 更新应用后,将阻止浏览器使用过时资产。
静态资产的交付基于 终结点路由,因此它适用于其他终结点感知功能,例如授权。 它旨在处理所有 UI 框架,包括 Blazor、Razor、Pages 和 MVC。
映射静态资产具有以下优势:
- 在应用中,对所有资产进行构建时压缩,包括 JavaScript(JS)和样式表,但不包括已压缩的图像和字体资产。
Gzip (
Content-Encoding: gz) 压缩在开发期间使用。 Gzip 和 Brotli (Content-Encoding: br) 压缩在发布期间都使用。 - 使用每个文件的内容的 SHA-256 哈希的 Base64 编码字符串在生成时为所有资产创建指纹。 这可以防止重用旧版本的文件,即使缓存了旧文件。 指纹资产是使用
immutable指令缓存的,这会导致浏览器在更改之前永远不会再次请求资产。 对于不支持该指令的immutable浏览器,将添加一个max-age指令 。
映射静态资产不提供用于缩小或其他文件转换的功能。 缩小通常由自定义代码或 第三方工具处理。
若要在 ASP.NET Core 中启用静态文件处理,请调用 UseStaticFiles。
默认情况下,静态文件存储在项目的 Web 根 目录中。 默认目录是 {CONTENT ROOT}/wwwroot,其中 {CONTENT ROOT} 占位符是应用的 内容根目录。 只有 wwwroot 文件夹中的文件可寻址,因此无需担心其余代码。
在运行时,静态 Web 资产会由静态文件中间件返回,前提是请求中包含已应用的资产修改和内容类型标头。 设置ETag、Last-Modified和Content-Type标头。
静态文件中间件启用静态文件服务,当在应用的请求处理管道中调用UseStaticFiles时被使用。 文件从指定IWebHostEnvironment.WebRootPathWebRootFileProvider路径提供,通常默认为 Web 根文件夹wwwroot。
还可以从 引用的项目和包中提供静态网站资源。
更改 Web 根目录
UseWebRoot如果要更改 Web 根,请使用该方法。 有关详细信息,请参阅 ASP.NET 核心基础知识概述。
阻止在项目文件中发布wwwroot包含<Content>项目项的文件。 以下示例阻止在 wwwroot/local 及其子目录中发布内容:
<ItemGroup>
<Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>
采用 CreateBuilder 方法可将内容根目录设置为当前目录:
var builder = WebApplication.CreateBuilder(args);
采用 CreateDefaultBuilder 方法可将内容根目录设置为当前目录:
Host.CreateDefaultBuilder(args)
在调用 UseHttpsRedirection后的请求处理管道中,调用 MapStaticAssets 应用的请求处理管道,以启用从应用的 Web 根目录提供静态文件:
app.MapStaticAssets();
在调用 UseHttpsRedirection后的请求处理管道中,调用 UseStaticFiles 应用的请求处理管道,以启用从应用的 Web 根目录提供静态文件:
app.UseStaticFiles();
可通过 Web 根目录的相关路径访问静态文件。
若要访问指定位置的图像,请执行以下步骤 wwwroot/images/favicon.png:
- URL 格式:
https://{HOST}/images/{FILE NAME}- 占位符号
{HOST}是主机。 - 占位符
{FILE NAME}是文件名。
- 占位符号
- 示例
- 绝对 URL:
https://localhost:5001/images/favicon.png - 根目录相对 URL:
images/favicon.png
- 绝对 URL:
在Blazor应用中,images/favicon.png从应用的favicon.png文件夹加载图标图像(wwwroot/images)。
<link rel="icon" type="image/png" href="images/favicon.png" />
在 Razor Pages 和 MVC 应用中,平铺字符 ~ 指向 Web 根。 在以下示例中,~/images/favicon.png从应用的favicon.png文件夹中加载图标图像(wwwroot/images):
<link rel="icon" type="image/png" href="~/images/favicon.png" />
对中间件管道进行短路
为了避免在匹配静态资产后运行整个中间件管道的默认行为,请在UseStaticFiles上调用ShortCircuitMapStaticAssets。 调用 ShortCircuit 会立即执行终结点并返回响应,从而阻止其他中间件执行静态资产请求:
app.MapStaticAssets().ShortCircuit();
在开发过程中控制静态文件缓存
在开发环境中运行时(例如在 Visual Studio 热重载 开发测试期间)时,框架会重写缓存标头,以防止浏览器缓存静态文件。 这有助于确保在文件更改时使用最新版本的文件,从而避免过时内容的问题。 在生产环境中,设置了正确的缓存标头,允许浏览器按预期缓存静态资产。
若要禁用此行为,请在开发环境的应用设置文件中设置为 EnableStaticAssetsDevelopmentCachingtrue (appsettings.Development.json)。
非Development 环境中的静态文件
在本地运行应用时,静态 Web 资产仅在开发环境中启用。 若要在本地开发和测试期间为除开发以外的环境启用静态文件(例如,在过渡环境中),请调用 UseStaticWebAssetsWebApplicationBuilder。
Warning
调用UseStaticWebAssets以获取特定的环境,避免在生产环境中激活此功能,因为它会从磁盘上的其他位置提供文件,而不是从项目目录中的位置。 本节中的示例检查暂存环境是否使用 IsStaging。
if (builder.Environment.IsStaging())
{
builder.WebHost.UseStaticWebAssets();
}
通过 IWebHostEnvironment.WebRootPath 在 Web 根目录之外提供文件
如果 IWebHostEnvironment.WebRootPath 设置为不同于 wwwroot 的文件夹,将会展示以下默认行为:
- 在开发环境中,如果具有相同名称的资产既在
wwwroot中又在分配到wwwroot的其他文件夹中,则静态资产从WebRootPath中提供。 - 在开发以外的任何环境中,将从文件夹中提供重复的 WebRootPath 静态资产。
请考虑从空 Web 模板创建的 Web 应用:
- 在
Index.html和wwwroot中包含一个wwwroot-custom文件。 - 文件
Program更新以设置WebRootPath = "wwwroot-custom"。
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
WebRootPath = "wwwroot-custom"
});
默认情况下,对于请求 /:
- 在开发环境中,返回
wwwroot/Index.html。 - 在除开发之外的任何环境中,
wwwroot-custom/Index.html将返回。
使用以下方法 wwwroot-custom ,来确保始终返回来自的资产:
删除
wwwroot中重名资产。将
ASPNETCORE_ENVIRONMENT中的Properties/launchSettings.json设置为Development以外的任何值。在应用的项目文件中,通过将
<StaticWebAssetsEnabled>设置为false来禁用静态 Web 资源。 警告: 禁用静态 Web 资产会 Razor 禁用类库。将以下 XML 添加到项目文件:
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
以下代码更新 WebRootPath 为非开发值(Staging),保证从 wwwroot-custom 中返回重复内容,而不是 wwwroot:
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
EnvironmentName = Environments.Staging,
WebRootPath = "wwwroot-custom"
});
静态文件中间件
静态文件中间件在特定静态文件场景下提供静态文件服务,通常结合映射静态资源终结点路由约定(MapStaticAssets)一起使用。
静态文件中间件在请求处理中被包含,当在应用的请求处理管道中调用UseStaticFiles时,通常是在添加映射静态资产终结点约定(MapStaticAssets)之后。
映射静态资产终结点约定用于面向 .NET 9 或更高版本的应用。 静态文件中间件必须在面向 .NET 9 之前的 .NET 版本的应用中使用。
静态文件中间件提供静态文件,但它不提供与“映射静态资源”端点惯例相同的优化级别。 仅依赖静态文件中间件时,地图静态资产终结点约定的构建时压缩和指纹功能将不可用。
端点约定已针对应用在运行时可识别的资源进行优化,以便更高效地提供服务。 如果应用提供来自其他位置(例如磁盘或嵌入资源)的资产,则应使用静态文件中间件。
静态文件中间件支持本文中介绍的以下功能,但不支持映射静态资源终结点约定:
通过 UseStaticFiles 在 Web 根目录之外提供文件
请考虑以下目录结构,其中静态文件位于一个名为的文件夹中,而不是应用程序的ExtraStaticFiles下:
wwwrootcssimagesjs
ExtraStaticFilesimagesred-rose.jpg
通过配置静态文件中间件的新实例,请求可以访问 red-rose.jpg :
以下 API 的命名空间:
using Microsoft.Extensions.FileProviders;
在对现有调用 MapStaticAssets (.NET 9 或更高版本) 或 UseStaticFiles (.NET 8 或更早版本) 之后的请求处理管道中:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
RequestPath = "/static-files"
});
在前面的代码中, ExtraStaticFiles 目录层次结构通过 static-files URL 段公开。 对 https://{HOST}/StaticFiles/images/red-rose.jpg 的请求(其中 {HOST} 占位符是主机)为 red-rose.jpg 文件提供服务。
以下标记引用 ExtraStaticFiles/images/red-rose.jpg:
<img src="static-files/images/red-rose.jpg" alt="A red rose" />
对于前面的示例,Razor Pages 和 MVC 视图(src="~/StaticFiles/images/red-rose.jpg")中支持波浪号斜杠表示法,但 Razor 应用中的 Blazor 组件不支持。
从多个位置提供文件
本部分中的指南适用于 Razor Pages 和 MVC 应用。 有关适用于 Blazor Web App 的指南,请参阅 ASP.NET Core Blazor 静态文件。
请考虑显示公司徽标的以下标记:
<img src="~/logo.png" asp-append-version="true" alt="Company logo">
开发人员打算使用 映像标记帮助程序 来追加版本,并从自定义位置(名为 ExtraStaticFiles文件夹)提供文件。
以下示例调用 MapStaticAssets 从 wwwroot 提供文件服务,以及使用 UseStaticFiles 从 ExtraStaticFiles 提供文件服务:
在对现有调用 MapStaticAssets (.NET 9 或更高版本) 或 UseStaticFiles (.NET 8 或更早版本) 之后的请求处理管道中:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});
以下示例调用UseStaticFiles两次,以分别从wwwroot 和 ExtraStaticFiles 提供文件。
在现有调用 UseStaticFiles后的请求处理管道中:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});
使用前面的代码来显示文件ExtraStaticFiles/logo.png。 但是,图像标记助手(AppendVersion)未应用,因为标记帮助程序依赖于WebRootFileProvider,而WebRootFileProvider尚未更新以包含文件夹。
以下代码使用 WebRootFileProvider 将 ExtraStaticFiles 更新以包含 CompositeFileProvider 文件夹。 这使图像标签帮助程序能够将版本应用于ExtraStaticFiles文件夹中的图像。
以下 API 的命名空间:
using Microsoft.Extensions.FileProviders;
在对现有调用 MapStaticAssets (.NET 9 或更高版本)或 UseStaticFiles (.NET 8 或更早版本)之前的请求处理管道中:
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider, newPathProvider);
app.Environment.WebRootFileProvider = compositeProvider;
UseStaticFiles 和 UseFileServer 默认为指向 wwwroot 的文件提供程序。 可使用其他文件提供程序提供 UseStaticFiles 和 UseFileServer 的其他实例,从多个位置提供文件。 有关详细信息,请参阅 使用 UseFileServer for wwwroot 时仍然需要 UseStaticFiles(dotnet/AspNetCore.Docs #15578)。
设置 HTTP 响应标头
使用 StaticFileOptions 设置 HTTP 响应标头。 除了将静态文件中间件配置为提供静态文件外,以下代码将标头设置为 Cache-Control 604,800 秒(一周)。
以下 API 的命名空间:
using Microsoft.AspNetCore.Http;
在对现有调用 MapStaticAssets (.NET 9 或更高版本) 或 UseStaticFiles (.NET 8 或更早版本) 之后的请求处理管道中:
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append(
"Cache-Control", "public, max-age=604800");
}
});
大量资产集合
处理大量资产(被视为大约 1,000 个或更多资产)时,我们建议使用捆绑程序来减少应用程序所提供的资产总数,并合并MapStaticAssetsUseStaticFiles。
MapStaticAssets 及时地加载在资源生成过程中捕获的预先计算的元数据,以支持压缩、缓存和指纹。 这些功能的成本是应用占用更大的内存。 对于频繁访问的资产,通常值得花费。 对于不经常访问的资产,权衡后可能不值得去承担这些成本。
如果不使用捆绑,我们建议结合 MapStaticAssets 和 UseStaticFiles。 以下示例演示了该方法。
在项目文件中(.csproj),使用 StaticWebAssetEndpointExclusionPattern MSBuild 属性从用于 MapStaticAssets 的最终清单中过滤终结点。 被排除的文件由 UseStaticFiles 提供,不受益于压缩、缓存和指纹识别。
设置值 StaticWebAssetEndpointExclusionPattern时,请保留 $(StaticWebAssetEndpointExclusionPattern) 以保留框架的默认排除模式。 在分号分隔的列表中添加其他模式。
在以下示例中,排除模式会将 lib/icons 文件夹中的静态文件排除,这表示一批假设的图标:
<StaticWebAssetEndpointExclusionPattern>
$(StaticWebAssetEndpointExclusionPattern);lib/icons/**
</StaticWebAssetEndpointExclusionPattern>
在 app.UseHttpsRedirection(); 文件中经过 HTTPS 重定向中间件(Program)处理后:
- 调用 UseStaticFiles 以处理排除的文件(
lib/icons/**)和未涵盖 MapStaticAssets的任何其他文件。 - 调用MapStaticAssets,然后在UseStaticFiles之后处理关键文件(CSS、JS、图像)。
app.UseStaticFiles();
app.UseAuthorization();
app.MapStaticAssets();
静态文件授权
当应用采用 回退授权策略时,所有未显式指定授权策略的请求都需要授权,包括授权中间件处理请求后对静态文件的请求。 通过将 AllowAnonymousAttribute 应用于静态文件的端点构建器,允许匿名访问静态文件:
app.MapStaticAssets().Add(endpointBuilder =>
endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()));
当应用采用 回退授权策略时,所有未显式指定授权策略的请求都需要授权,包括授权中间件处理请求后对静态文件的请求。 ASP.NET Core 模板允许通过在调用UseStaticFiles之前调用UseAuthorization来匿名访问静态文件。 大多数应用都遵循此模式。 如果在授权中间件之前调用静态文件中间件:
- 不会对静态文件执行任何授权检查。
- 静态文件中间件提供的静态文件,如 Web 根目录下的文件(通常为
wwwroot),可以公开访问。
根据授权提供静态文件:
- 确认应用设置 回退授权策略 以要求经过身份验证的用户。
- 将静态文件存储在应用的 Web 根目录之外。
- 调用 UseAuthorization后,调用 UseStaticFiles,指定 Web 根外部静态文件文件夹的路径。
以下 API 的命名空间:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;
服务注册:
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
在调用 UseAuthorization后的请求处理管道中:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "SecureStaticFiles")),
RequestPath = "/static-files"
});
以下 API 的命名空间:
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;
在 Startup.ConfigureServices中:
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
在Startup.Configure调用UseAuthorization之后:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "SecureStaticFiles")),
RequestPath = "/static-files"
});
在前面的代码中,回退授权策略需要经过身份验证的用户。 指定其自己的授权要求的终结点(如控制器和 Razor 页面)不使用回退授权策略。 例如,具有 Razor 或 [AllowAnonymous] 的 [Authorize(PolicyName="MyPolicy")] Pages、控制器或操作方法使用应用的授权属性,而不是回退授权策略。
RequireAuthenticatedUser 将 DenyAnonymousAuthorizationRequirement 添加到当前实例,这将强制对当前用户进行身份验证。
存储在应用的 Web 根目录中的静态资产是可公开访问的,因为之前UseStaticFiles调用默认的静态文件中间件(UseAuthorization)。 文件夹中的 SecureStaticFiles 静态资产需要身份验证。
还有一种根据授权提供文件的方法是:
- 将文件存储在 Web 根目录之外以及可以被静态文件中间件访问的任何目录之外。
- 通过应用授权的操作方法提供文件服务,并返回 FileResult 对象。
从Razor页面(Pages/BannerImage.cshtml.cs):
public class BannerImageModel : PageModel
{
private readonly IWebHostEnvironment _env;
public BannerImageModel(IWebHostEnvironment env) => _env = env;
public PhysicalFileResult OnGet()
{
var filePath = Path.Combine(
_env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
}
来自控制器(Controllers/HomeController.cs):
[Authorize]
public IActionResult BannerImage()
{
var filePath = Path.Combine(
_env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
上述方法要求对每个文件使用一个页面或终结点。
以下路由终结点示例返回经过身份验证的用户的文件。
在 Program 文件中:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});
...
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileName);
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
以下路由终结点示例上传管理员角色(“”admin)中经过身份验证的用户的文件。
在 Program 文件中:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});
...
// IFormFile uses memory buffer for uploading. For handling large
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://free.blessedness.top/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker,
HttpContext context) =>
{
// Don't rely on the value in 'file.FileName', as it's only metadata that can
// be manipulated by the end-user. Consider the 'Utilities.IsFileValid' method
// that takes an 'IFormFile' and validates its signature within the
// 'AllowedFileSignatures'.
var fileSaveName = Guid.NewGuid().ToString("N") +
Path.GetExtension(file.FileName);
await SaveFileWithCustomFileName(file, fileSaveName);
context.Response.Headers.Append("Location", linker.GetPathByName(context,
"GetFileByName", new { fileName = fileSaveName}));
return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");
在 Startup.ConfigureServices中:
services.AddAuthorization(options =>
{
options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});
在 Startup.Configure中:
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileName);
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
以下代码上传管理员角色(“”admin)中经过身份验证的用户的文件。
在 Startup.ConfigureServices中:
services.AddAuthorization(options =>
{
options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});
在 Startup.Configure中:
// IFormFile uses memory buffer for uploading. For handling large
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://free.blessedness.top/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker,
HttpContext context) =>
{
// Don't rely on the value in 'file.FileName', as it's only metadata that can
// be manipulated by the end-user. Consider the 'Utilities.IsFileValid' method
// that takes an 'IFormFile' and validates its signature within the
// 'AllowedFileSignatures'.
var fileSaveName = Guid.NewGuid().ToString("N") +
Path.GetExtension(file.FileName);
await SaveFileWithCustomFileName(file, fileSaveName);
context.Response.Headers.Append("Location", linker.GetPathByName(context,
"GetFileByName", new { fileName = fileSaveName}));
return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");
目录浏览
目录浏览允许在指定目录中列出目录。
出于安全考虑,目录浏览默认处于禁用状态。 有关详细信息,请参阅静态文件的安全注意事项。
使用以下 API 启用目录浏览:
在下面的示例中:
-
images应用根目录中的文件夹保存用于目录浏览的图像。 - 浏览图像的请求路径为
/DirectoryImages。 - 调用UseStaticFiles和设置FileProviderStaticFileOptions可显示指向各个文件的浏览器链接。
以下 API 的命名空间:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
服务注册:
builder.Services.AddDirectoryBrowser();
在对现有调用 MapStaticAssets (.NET 9 或更高版本) 或 UseStaticFiles (.NET 8 或更早版本) 之后的请求处理管道中:
var fileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/DirectoryImages";
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
以下 API 的命名空间:
using Microsoft.Extensions.FileProviders;
using System.IO;
在 Startup.ConfigureServices中:
services.AddDirectoryBrowser();
在现有对 Startup.Configure 的调用之后执行 UseStaticFiles:
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/DirectoryImages"
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/DirectoryImages"
});
前面的代码允许通过 URL wwwroot/images 浏览 https://{HOST}/DirectoryImages 文件夹的目录,并提供每个文件和文件夹的链接,其中 {HOST} 占位符表示主机。
AddDirectoryBrowser 添加目录浏览中间件所需的服务,包括 HtmlEncoder。 这些服务可能由其他调用添加,例如 AddRazorPages,我们建议调用 AddDirectoryBrowser 以确保添加服务。
提供默认文档
设置默认页面为访问者提供网站的起点。 若要从 wwwroot 中提供默认文件而不要求请求 URL 包含文件名,请调用该方法 UseDefaultFiles 。
UseDefaultFiles 是一个不提供文件服务的 URL 重写工具。 在对 .NET 9 或更高版本的 MapStaticAssets 调用或 .NET 8 或更低版本的 UseStaticFiles 调用之前的请求处理管道阶段:
app.UseDefaultFiles();
使用 UseDefaultFiles 请求对 wwwroot 中的文件夹搜索:
default.htmdefault.htmlindex.htmindex.html
如同请求包含了文件名一样,提供从列表中找到的第一个文件。 浏览器 URL 继续反映请求的 URI。
以下代码将默认文件名更改为 default-document.html:
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("default-document.html");
app.UseDefaultFiles(options);
合并静态文件、默认文档和目录浏览
UseFileServer 结合了 UseStaticFiles、UseDefaultFiles 和 UseDirectoryBrowser(可选)的功能。
在对现有调用 MapStaticAssets (.NET 9 或更高版本)或 UseStaticFiles (.NET 8 或更早版本)之后的请求处理管道中,调用 UseFileServer 以启用静态文件和默认文件的服务:
app.UseFileServer();
前面的示例未启用目录浏览。
以下代码支持提供静态文件、默认文件和目录浏览。
服务注册:
builder.Services.AddDirectoryBrowser();
在现有调用 UseStaticFiles后的请求处理管道中:
app.UseFileServer(enableDirectoryBrowsing: true);
在 Startup.ConfigureServices中:
services.AddDirectoryBrowser();
在现有对 Startup.Configure 的调用之后执行 UseStaticFiles:
app.UseFileServer(enableDirectoryBrowsing: true);
对于主机地址(/),在默认UseFileServer页面(Razor)或默认 MVC 视图(Pages/Index.cshtml)之前,返回默认 HTML 文档。
考虑以下目录层次结构:
wwwrootcssimagesjs
ExtraStaticFilesimageslogo.png
default.html
以下代码允许提供静态文件、默认文件和目录浏览 ExtraStaticFiles。
以下 API 的命名空间:
using Microsoft.Extensions.FileProviders;
服务注册:
builder.Services.AddDirectoryBrowser();
在现有调用 UseStaticFiles后的请求处理管道中:
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
RequestPath = "/static-files",
EnableDirectoryBrowsing = true
});
以下 API 的命名空间:
using Microsoft.Extensions.FileProviders;
using System.IO;
在 Startup.ConfigureServices中:
services.AddDirectoryBrowser();
在现有对 Startup.Configure 的调用之后执行 UseStaticFiles:
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "ExtraStaticFiles")),
RequestPath = "/static-files",
EnableDirectoryBrowsing = true
});
必须在 AddDirectoryBrowser 属性值为 EnableDirectoryBrowsing 时调用 true。
使用前面的文件层次结构和代码,URL 解析,如下表所示( {HOST} 占位符是主机)。
| URI | 响应文件 |
|---|---|
https://{HOST}/static-files/images/logo.png |
ExtraStaticFiles/images/logo.png |
https://{HOST}/static-files |
ExtraStaticFiles/default.html |
如果目录中不存在默认命名的文件 ExtraStaticFiles , https://{HOST}/static-files 则返回包含可单击链接的目录列表,其中 {HOST} 占位符是主机。
UseDefaultFiles 和 UseDirectoryBrowser 执行从不带尾部 / 的目标 URI 到带尾部 / 的目标 URI 的客户端重定向。 例如,从 https://{HOST}/static-files (无尾随 /)到 https://{HOST}/static-files/ (包括尾随 /)。 除非使用ExtraStaticFiles/选项,否则在RedirectToAppendTrailingSlash目录中的相对 URL,如果没有尾部斜杠(DefaultFilesOptions),将被视为无效。
将文件扩展名映射到 MIME 类型
Note
有关适用于 Blazor 应用的指南,请参阅 ASP.NET Core Blazor 静态文件。
使用 FileExtensionContentTypeProvider.Mappings 来添加或修改文件扩展名至 MIME 内容类型的映射。 在以下示例中,多个文件扩展名映射到已知的 MIME 类型。 该 .rtf 扩展将被替换,并 .mp4 被删除:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
...
// 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
{
ContentTypeProvider = provider
});
如果有多个要配置的静态文件选项,也可以使用以下命令设置提供程序 StaticFileOptions:
var provider = new FileExtensionContentTypeProvider();
...
builder.Services.Configure<StaticFileOptions>(options =>
{
options.ContentTypeProvider = provider;
});
app.UseStaticFiles();
在 Startup.Configure中:
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 = "/images",
ContentTypeProvider = provider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/images"
});
有关详细信息,请参阅 MIME 内容类型。
非标准内容类型
静态文件中间件可理解近 400 种已知文件内容类型。 如果用户请求文件类型未知的文件,则静态文件中间件将请求传递给管道中的下一个中间件。 如果没有中间件处理请求,则返回“404 未找到”响应。 如果启用了目录浏览,则在目录列表中会显示该文件的链接。
以下代码支持提供未知内容类型,并将未知文件呈现为图像:
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
使用前面的代码,请求的文件含未知内容类型时,以图像形式返回请求。
Warning
启用 ServeUnknownFileTypes 会形成安全隐患。 它默认处于禁用状态,不建议使用。 将文件扩展名映射到 MIME 类型 可提供更安全的替代方法,用于为具有非标准扩展名的文件提供服务。
提供自定义静态文件清单
staticAssetsManifestPath如果是null,IHostEnvironment.ApplicationName则用于查找清单。 或者,指定清单文件的完整路径。 如果使用相对路径,框架将在AppContext.BaseDirectory中搜索该文件。
静态文件的安全注意事项
Warning
UseDirectoryBrowser 和 UseStaticFiles 可能会泄漏机密。 强烈建议在生产中禁用目录浏览。 请仔细查看哪些目录是通过 UseStaticFiles 或 UseDirectoryBrowser 启用的。 整个目录及其子目录均可公开访问。 将适合公开的文件存储在专用目录中,如 <content_root>/wwwroot。 将这些文件与 MVC 视图、Razor Pages 和配置文件等分开。
使用 UseDirectoryBrowser 和 UseStaticFiles 公开的内容的 URL 受大小写和基础文件系统字符限制的影响。 例如,Windows 不区分大小写,但 macOS 和 Linux 区分大小写。
托管于 IIS 中的 ASP.NET Core 应用使用 ASP.NET Core 模块将所有请求转发到应用,包括静态文件请求。 不使用 IIS 静态文件处理程序,并且没有机会处理请求。
在 IIS Manager 中完成以下步骤,删除服务器或网站级别的 IIS 静态文件处理程序:
- 转到“模块”功能。
- 在列表中选择 StaticFileModule。
- 单击“操作”侧栏中的“删除”。
Warning
如果启用了 IIS 静态文件处理程序且 ASP.NET Core 模块配置不正确,则会提供静态文件。 例如,如果文件未 web.config 部署,则会发生此情况。
- 将代码文件(包括
.cs和.cshtml)放在应用项目的 Web 根目录之外。 这样就在应用的客户端内容和基于服务器的代码间创建了逻辑分隔。 可以防止服务器端代码泄漏。
MSBuild 属性
下表显示了静态文件 MSBuild 属性和元数据说明。
| 资产 | Description |
|---|---|
EnableDefaultCompressedItems |
启用默认压缩包括/排除模式。 |
CompressionIncludePatterns |
要包括用于压缩的文件模式的分号分隔列表。 |
CompressionExcludePatterns |
要从压缩中排除的文件模式的分号分隔列表。 |
EnableDefaultCompressionFormats |
启用默认压缩格式(Gzip 和 Brotli)。 |
BuildCompressionFormats |
在构建期间使用的压缩格式。 |
PublishCompressionFormats |
发布期间要使用的压缩格式。 |
DisableBuildCompression |
在生成过程中禁用压缩。 |
CompressDiscoveredAssetsDuringBuild |
在构建过程中压缩发现的资产。 |
BrotliCompressionLevel |
Brotli 算法的压缩级别。 |
StaticWebAssetBuildCompressAllAssets |
压缩构建过程中所有的资产,而不是仅限于构建过程中发现或计算的那些资产。 |
StaticWebAssetPublishCompressAllAssets |
在发布期间压缩所有资产,而不仅仅是在构建过程中发现或计算的资产。 |
| 资产 | Description |
|---|---|
StaticWebAssetBasePath |
库中所有资产的基 URL 路径。 |
StaticWebAssetsFingerprintContent |
启用用于缓存破坏的内容指纹。 |
StaticWebAssetFingerprintingEnabled |
为静态 Web 资产启用指纹功能。 |
StaticWebAssetsCacheDefineStaticWebAssetsEnabled |
启用静态 Web 资产定义的缓存。 |
StaticWebAssetEndpointExclusionPattern |
排除终结点的模式。 |
| 物料组 | Description | Metadata |
|---|---|---|
StaticWebAssetContentTypeMapping |
将文件模式映射到终结点的内容类型和缓存标头。 |
Pattern、Cache |
StaticWebAssetFingerprintPattern |
定义用于将指纹应用于静态 Web 资产以用于缓存破坏的模式。 |
Pattern、Expression |
元数据说明:
Pattern:用于匹配文件的 glob 模式。 对于StaticWebAssetContentTypeMapping,它匹配文件以确定其内容类型(例如,*.jsJavaScript 文件)。StaticWebAssetFingerprintPattern用于标识需要特殊指纹处理的多扩展文件(例如*.lib.module.js)。Cache:指定Cache-Control匹配内容类型的标头值。 这将控制浏览器的缓存行为(例如对媒体文件进行max-age=3600, must-revalidate)。Expression:定义指纹标识插入文件名的方式。 默认值为#[.{FINGERPRINT}],在扩展之前插入指纹({FINGERPRINT}占位符)。
以下示例将位图文件模式 (.bmp) 映射到 image/bmp 内容类型,其中 {CACHE HEADER} 占位符表示 Cache-Control 标头,用于没有指纹的端点:
<ItemGroup>
<StaticWebAssetContentTypeMapping Include="image/bmp" Cache="{CACHE HEADER}" Pattern="*.bmp" />
</ItemGroup>
运行时配置选项
下表介绍了运行时配置选项。
| 配置密钥 | Description |
|---|---|
ReloadStaticAssetsAtRuntime |
启用开发时的静态资源热重载:提供经过修改的 Web 根目录文件(重新计算wwwroot,如需要重新压缩ETag),而不是使用构建时的清单版本。 默认情况下,仅在服务构建清单时启用,除非有明确设置。 |
DisableStaticAssetNotFoundRuntimeFallback |
当启用true时,会抑制用于服务于生成清单中不存在的新增文件的回退端点。 当 false 存在或不存在时,文件存在检查的 {**path} 回退(GET/HEAD)会记录一个警告,并使用计算得到的 ETag 为文件提供服务。 |
EnableStaticAssetsDevelopmentCaching |
当true时,保留资产描述符中的原始Cache-Control信息标头。 当false为空或缺失时,将Cache-Control标头重写为no-cache以避免在开发过程中出现过于激进的客户端缓存。 |
EnableStaticAssetsDevelopmentIntegrity |
当true运行时,会在资产描述符上保持完整性属性。 如果 false 不存在,则删除任何完整性属性,以防止在开发过程中文件发生更改时不匹配。 |