默认情况下,静态文件(如 HTML、CSS、图像和 JavaScript)是 ASP.NET Core 应用直接提供给客户端的资产。
有关添加或取代本文中指导的 Blazor 静态文件指导,请参阅 ASP.NET Core Blazor 静态文件。
提供静态文件
静态文件存储在项目的 Web 根目录中。 默认目录为 {content root}/wwwroot
,但可通过 UseWebRoot 方法更改目录。 有关详细信息,请参阅内容根目录和 Web 根目录。
采用 CreateBuilder 方法可将内容根目录设置为当前目录:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
可通过 Web 根目录的相关路径访问静态文件。 例如,Web 应用程序项目模板包含 文件夹中的多个文件夹:
wwwroot
css
js
lib
请考虑到带有 wwwroot/images/MyImage.jpg
文件的应用。 用于访问 images
文件夹中的文件的 URI 格式为 https://<hostname>/images/<image_file_name>
。 例如: https://localhost:5001/images/MyImage.jpg
映射静态资源路由终结点约定 (MapStaticAssets
)
创建性能良好的 Web 应用需要优化将资源传递到浏览器的过程。 MapStaticAssets 可能的优化包括:
- 提供一次给定资产,直到文件发生更改或浏览器清除其缓存为止。 设置 ETag 和 上次修改 的标头。
- 更新应用后,阻止浏览器使用旧或失效的资源。 设置 Last-Modified 标头。
- 设置正确的缓存标头。
- 使用 缓存中间件。
- 尽可能提供资产的压缩版本。 此优化不包括缩小。
- 使用 CDN 为离用户更近的资产提供服务。
- 指纹资产,以防止重复使用旧版本的文件。
MapStaticAssets
:
- 将生成过程中收集有关静态 Web 资产的信息与运行时库集成,该库处理此信息以优化向浏览器提供的文件。
- 用于优化应用中的静态资产交付的路由终结点约定。 它旨在处理所有 UI 框架,包括 Blazor、Razor、Pages 和 MVC。
MapStaticAssets
与 UseStaticFiles
MapStaticAssets 在 .NET 9 或更高版本的 ASP.NET Core 中提供。 UseStaticFiles 必须在 .NET 9 之前的版本中使用。
UseStaticFiles
提供静态文件,但它没有达到 MapStaticAssets
相同的优化级别。
MapStaticAssets
进行了优化,以提供应用在运行时了解的资产。 如果应用服务来自其他位置(如磁盘或嵌入资源)的资产,则应使用 UseStaticFiles
。
映射静态资产提供在调用 UseStaticFiles
时不可用的以下优点:
- 在应用中,对所有资产进行构建时压缩,包括 JavaScript(JS)和样式表,但不包括已压缩的图像和字体资产。
Gzip (
Content-Encoding: gz
) 压缩在开发期间使用。 发布期间使用附带 Brotli (Content-Encoding: br
) 压缩的 Gzip。 - 使用每个文件的内容的 SHA-256 哈希的 Base64 编码字符串在生成时为所有资产创建指纹。 这可以防止重用旧版本的文件,即使缓存了旧文件。 指纹资产是使用
immutable
指令缓存的,这会导致浏览器在更改之前永远不会再次请求资产。 对于不支持该指令的immutable
浏览器,将添加一个max-age
指令 。 - 在 Visual Studio 热重载开发测试期间:
- 从资产中删除完整性信息,以避免在应用运行时更改文件时出现问题。
- 静态资产不会缓存,以确保浏览器始终检索当前内容。
映射静态资产不提供用于缩小或其他文件转换的功能。 缩小通常由自定义代码或 第三方工具处理。
使用 UseStaticFiles
支持以下功能,但使用 MapStaticAssets
不支持这些功能:
- 从磁盘或嵌入资源或其他位置提供文件
- 在 Web 根目录外提供文件服务
- 设置 HTTP 响应标头
- 目录浏览
- 提供默认文档
FileExtensionContentTypeProvider
- 从多个位置提供文件
- 从磁盘或嵌入资源或其他位置提供文件
- 在 Web 根目录外提供文件服务
- 设置 HTTP 响应标头
- 目录浏览
- 提供默认文档
FileExtensionContentTypeProvider
- 从多个位置提供文件
在 Web 根目录中提供文件
默认 Web 应用模板在 MapStaticAssets 中调用 Program.cs
方法,这将允许提供静态文件:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.MapStaticAssets();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
无参数 MapStaticAssets
方法重载将 Web 根目录中的文件标记为可用。 以下标记引用 wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
在上面的代码标记中,波形符 ~
指向 Web 根目录。
在网站根目录之外提供文件
考虑一个目录层次结构,其中要提供的静态文件位于 Web 根目录之外:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
按如下方式配置静态文件中间件后,请求可访问 red-rose.jpg
文件:
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); //Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
在前面的代码中,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 根目录提供静态文件外,以下代码还设置 标头:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var cacheMaxAgeOneWeek = (60 * 60 * 24 * 7).ToString();
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
ctx.Context.Response.Headers.Append(
"Cache-Control", $"public, max-age={cacheMaxAgeOneWeek}");
}
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
上面的代码使静态文件在本地缓存中公开提供一周。
静态文件授权
ASP.NET Core 模板在调用 MapStaticAssets 之前调用 UseAuthorization。 大多数应用都遵循此模式。 在授权中间件之前调用 MapStaticAssets
时:
- 不会对静态文件执行任何授权检查。
- 由静态文件中间件提供的静态文件(例如
wwwroot
下的文件)可公开访问。
若要根据授权提供静态文件,请参阅 静态文件授权。
从多个位置提供文件
请考虑以下显示 Razor 文件的 /MyStaticFiles/image3.png
页面:
@page
<p> Test /MyStaticFiles/image3.png</p>
<img src="~/image3.png" class="img" asp-append-version="true" alt="Test">
UseStaticFiles
和 UseFileServer
默认为指向 wwwroot
的文件提供程序。 可使用其他文件提供程序提供 UseStaticFiles
和 UseFileServer
的其他实例,从多个位置提供文件。 以下示例调用 UseStaticFiles
两次以提供来自 wwwroot
和 MyStaticFiles
的文件:
app.UseStaticFiles();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"))
});
使用上述代码:
- 将显示
/MyStaticFiles/image3.png
文件。 - 由于图像标记帮助程序AppendVersion依赖于 WebRootFileProvider,因此未应用该标记帮助程序。
WebRootFileProvider
尚未更新为包含MyStaticFiles
文件夹。
以下代码会更新 WebRootFileProvider
,使图像标记帮助程序能够提供版本:
var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles"));
var compositeProvider = new CompositeFileProvider(webRootProvider,
newPathProvider);
// Update the default provider.
app.Environment.WebRootFileProvider = compositeProvider;
app.MapStaticAssets();
注释
上述方法适用于 Razor Pages 和 MVC 应用。 有关适用于 Blazor Web App 的指南,请参阅 ASP.NET Core Blazor 静态文件。
通过更新 IWebHostEnvironment.WebRootPath 提供 wwwroot 外的文件
当 IWebHostEnvironment.WebRootPath 设置为 wwwroot
以外的文件夹时:
- 在开发环境中,在
wwwroot
和更新的IWebHostEnvironment.WebRootPath
中发现的静态资产由wwwroot
提供。 - 在开发环境以外的任何环境中,重复的静态资产会从更新的
IWebHostEnvironment.WebRootPath
文件夹提供。
请考虑使用空 Web 模板创建的 Web 应用:
在
Index.html
和wwwroot
中包含一个wwwroot-custom
文件。使用以下设置了
Program.cs
的已更新WebRootPath = "wwwroot-custom"
文件:var builder = WebApplication.CreateBuilder(new WebApplicationOptions { Args = args, // Look for static files in "wwwroot-custom" WebRootPath = "wwwroot-custom" }); var app = builder.Build(); app.UseDefaultFiles(); app.MapStaticAssets(); app.Run();
在前面的代码中,请求 /
:
- 在开发环境中,返回
wwwroot/Index.html
- 在开发环境以外的任何环境中,返回
wwwroot-custom/Index.html
若要确保返回 wwwroot-custom
中的资产,请使用以下方法之一:
在
wwwroot
中删除重复命名的资产。将
"ASPNETCORE_ENVIRONMENT"
中的Properties/launchSettings.json
设置为"Development"
以外的任何值。通过在项目文件中设置
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
,完全禁用静态 Web 资产。 警告,禁用静态 Web 资产会禁用 Razor 类库。将以下 XML 添加到项目文件:
<ItemGroup> <Content Remove="wwwroot\**" /> </ItemGroup>
以下代码将 IWebHostEnvironment.WebRootPath
更新为非开发值,从而保证从 wwwroot-custom
(而不是 wwwroot
)返回重复内容:
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
Args = args,
// Examine Hosting environment: logging value
EnvironmentName = Environments.Staging,
WebRootPath = "wwwroot-custom"
});
var app = builder.Build();
app.Logger.LogInformation("ASPNETCORE_ENVIRONMENT: {env}",
Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"));
app.Logger.LogInformation("app.Environment.IsDevelopment(): {env}",
app.Environment.IsDevelopment().ToString());
app.UseDefaultFiles();
app.MapStaticAssets();
app.Run();