ASP.NET Core 中的靜態檔案
注意
這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。
警告
不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支援原則。 如需目前版本,請參閱本文的 .NET 8 版本。
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
資料夾內包含數個資料夾:
wwwroot
css
js
lib
請考慮具有 wwwroot/images/MyImage.jpg
檔案的應用程式。 存取 images
資料夾中檔案的 URI 格式為 https://<hostname>/images/<image_file_name>
。 例如,https://localhost:5001/images/MyImage.jpg
MapStaticAssets
建立高效能的 Web 應用程式需要最佳化資產來傳遞至瀏覽器。 可能的最佳化包括:
- 提供指定的資產一次,直到檔案變更或瀏覽器清除其快取為止。 設定 ETag 標頭。
- 在更新應用程式之後,防止瀏覽器使用舊版或過時的資產。 設定上次的修改標頭。
- 設定適當的快取標頭。
- 使用快取中介軟體。
- 盡可能提供壓縮版本的資產。
- 使用 CDN 來提供更接近使用者的資產。
- 將提供給瀏覽器的資產大小降至最低。 此最佳化不包括縮製。
MapStaticAssets 是路由端點慣例,可優化應用程式中靜態資產的傳遞。 其設計目的是在與所有 UI 架構配合使用,包括 Blazor、Razor Pages 和 MVC。
UseStaticFiles
也提供靜態檔案儲存體,但不會提供與 MapStaticAssets
相同等級的最佳化。 如需 UseStaticFiles
和 MapStaticAssets
的比較,請參閱最佳化靜態網路資產傳遞。
在 Web 根目錄中提供檔案
預設的 Web 應用程式範本會在 Program.cs
中呼叫 MapStaticAssets 方法,以便提供靜態檔案:
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();
無參數的 UseStaticFiles
方法多載會將 Web 根目錄中的檔案標示為可提供。 下列標記參考 wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
在上述標記中,並排字元 ~
會指向 Web 根目錄。
提供 Web 根目錄外的檔案
請考慮使用目錄階層,以提供位於 Web 根目錄外部的靜態檔案:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
透過設定靜態檔案中介軟體,可讓要求存取 red-rose.jpg
檔案,如下所示:
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();
上述程式碼會透過 StaticFiles URI 區段公開 MyStaticFiles 目錄階層。 對 https://<hostname>/StaticFiles/images/red-rose.jpg
的要求提供 red-rose.jpg
檔案。
下列標記參考 MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
若要提供來自多個位置的檔案,請參閱提供來自多個位置的檔案。
設定 HTTP 回應標頭
StaticFileOptions 物件可用來設定 HTTP 回應標頭。 除了設定從 Web 根目錄提供靜態檔案,下列程式碼會設定 Cache-Control 標頭:
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 範本在呼叫 UseAuthorization 之前呼叫 MapStaticAssets。 大部分的應用程式都遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:
- 靜態檔案上不會執行授權檢查。
- 靜態檔案中介軟體所提供的靜態檔案 (例如
wwwroot
下的靜態檔案) 可公開存取。
若要根據授權提供靜態檔案:
- 將它們儲存在
wwwroot
之外。 - 在呼叫
UseAuthorization
之後,指定路徑,再呼叫UseStaticFiles
。 - 設定後援授權原則。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.MapRazorPages();
app.Run();
在上述程式碼中,後援授權原則會要求所有使用者都經過驗證。 指定其自己授權需求的控制器、Razor Pages 等端點,不會使用後援授權原則。 例如,使用 [AllowAnonymous]
或 [Authorize(PolicyName="MyPolicy")]
的 Razor Pages、控制器或動作方法,會使用套用的授權屬性,而不是後援授權原則。
RequireAuthenticatedUser 會將 DenyAnonymousAuthorizationRequirement 新增至目前的執行個體,這會強制使目前的使用者經驗證。
可公開存取 wwwroot
下的靜態資產,因為會在 UseAuthentication
之前呼叫預設的靜態檔案中介軟體 (app.UseStaticFiles();
)。 MyStaticFiles 資料夾中的靜態資產需要驗證。 範例程式碼會示範這一點。
根據授權提供檔案的替代方法是:
將它們儲存在
wwwroot
外部和可存取靜態檔案中介軟體的任何目錄。透過套用授權的動作方法來提供服務並傳回 FileResult 物件:
[Authorize] public class BannerImageModel : PageModel { private readonly IWebHostEnvironment _env; public BannerImageModel(IWebHostEnvironment env) => _env = env; public PhysicalFileResult OnGet() { var filePath = Path.Combine( _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg"); return PhysicalFile(filePath, "image/jpeg"); } }
上述方法需要每個檔案一個頁面或端點。 下列程式碼會為已驗證使用者傳回檔案或上傳檔案:
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
app.MapPost("/files",
async (IFormFile file, LinkGenerator linker, HttpContext context) =>
{
// Don't rely on the file.FileName as it is only metadata that can be
// manipulated by the end-user. See 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");
app.Run();
上述樣本中的 IFormFile 使用記憶體緩衝區來上傳。 若要處理大型檔案,請使用串流。 請參閱 使用串流上傳大型檔案儲存體
如需完整的範例,請參閱 StaticFileAuth GitHub 資料夾。
瀏覽目錄
「目錄瀏覽」允許列出指定目錄中的目錄清單。
基於安全考量,「目錄瀏覽」功能預設為停用。 如需詳細資訊,請參閱靜態檔案的安全性考量。
使用 AddDirectoryBrowser 和 UseDirectoryBrowser 啟用「目錄瀏覽」:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.MapStaticAssets();
var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";
// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
上述程式碼可讓您使用 URL https://<hostname>/MyImages
與每個檔案和資料夾的連結,來進行 wwwroot/images 資料夾的目錄瀏覽:
AddDirectoryBrowser
新增服務,目錄瀏覽中介軟體需要 HtmlEncoder 等服務。 這些服務可能會由其他呼叫 (例如 AddRazorPages) 新增,但我們建議呼叫 AddDirectoryBrowser
以確保會在所有應用程式中新增服務。
提供預設文件
[設定預設頁面] 為訪客在站台上提供了起點。 若要從 wwwroot
提供預設檔案,而不需要要求 URL 包含檔案名稱,請呼叫 UseDefaultFiles 方法:
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.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
您必須在 UseStaticFiles
之前先呼叫 UseDefaultFiles
,才能提供預設的檔案。 UseDefaultFiles
是 URL 重寫器,其無法提供檔案。
使用 UseDefaultFiles
,要求在 wwwroot
資料夾中搜尋:
default.htm
default.html
index.htm
index.html
從清單中找到的第一個檔案,就像用包含檔案名稱的要求所提供。 瀏覽器 URL 仍會繼續反應要求的 URI。 例如,在 樣本應用程式,對 https://localhost:<port>/def/
服務 default.html
要從 wwwroot/def
提出要求 。
下列程式碼會將預設檔案名稱變更為 mydefault.html
:
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 options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
預設文件的 UseFileServer
UseFileServer 結合 UseStaticFiles
、UseDefaultFiles
和 UseDirectoryBrowser
(選擇性) 的功能。
呼叫 app.UseFileServer
以便提供靜態檔案和預設檔案。 未啟用「目錄瀏覽」功能:
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.UseFileServer();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
下列程式碼可讓您提供靜態檔案、預設檔案和目錄瀏覽功能:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
請考慮下列目錄階層:
wwwroot
css
images
js
MyStaticFiles
defaultFiles
default.html
image3.png
images
MyImage.jpg
下列程式碼可讓您提供靜態檔案、預設檔案和 MyStaticFiles
的目錄瀏覽功能:
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
必須在 EnableDirectoryBrowsing
屬性值為 true
時呼叫 AddDirectoryBrowser。
使用上述檔案階層和程式碼時,URL 解析如下:
URI | 回應 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
目錄清單 |
https://<hostname>/StaticFiles/defaultFiles |
MyStaticFiles/defaultFiles/default.html |
https://<hostname>/StaticFiles/defaultFiles/image3.png |
MyStaticFiles/defaultFiles//image3.png |
如果 MyStaticFiles 目錄中沒有預設命名的檔案,則 https://<hostname>/StaticFiles
會傳回具有可點選連結的目錄清單:
UseDefaultFiles 和 UseDirectoryBrowser 會執行用戶端重新導向,從不含尾端 /
的目標 URI 重新導向至含尾端 /
的目標 URI。 例如,從 https://<hostname>/StaticFiles
到 https://<hostname>/StaticFiles/
。 除非使用 DefaultFilesOptions 的 RedirectToAppendTrailingSlash 選項,否則 StaticFiles 目錄內的相對 URL 若未含尾端斜線 (/
) 則會被視為無效。
FileExtensionContentTypeProvider
類別 FileExtensionContentTypeProvider 包含 Mappings 屬性,用作檔案副檔名到 MIME 內容類型的對應。 在下列範例中,已有數個副檔名對應至已知的 MIME 類型。 已取代 .rtf 副檔名,並已移除 .mp4:
using Microsoft.AspNetCore.StaticFiles;
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();
// 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
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
請參閱 MIME 內容類型。
非標準的內容類型
靜態檔案中介軟體可識別近 400 種已知的檔案內容類型。 如果使用者要求具有未知檔案類型的檔案,則靜態檔案中介軟體會將該要求傳遞至管線中的下一個中介軟體。 如果沒有中介軟體處理要求,則會傳回「404 找不到」回應。 如果啟用目錄瀏覽功能,則會在目錄清單中顯示檔案的連結。
下列程式碼可讓您提供未知的類型,並會將未知的檔案轉譯為影像:
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(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseAuthorization();
app.MapDefaultControllerRoute().WithStaticAssets();
app.MapRazorPages().WithStaticAssets();
app.Run();
使用上述程式碼時,系統會以影像來回應具有未知內容類型的檔案要求。
警告
啟用 ServeUnknownFileTypes 會有安全性風險。 預設為停用,亦不建議您使用。 FileExtensionContentTypeProvider 可提供更安全的替代方法,來提供非標準副檔名的檔案。
提供來自多個位置的檔案
請考慮顯示 /MyStaticFiles/image3.png
檔案的下列 Razor 頁面:
@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 靜態檔案。
靜態檔案的安全性考量
警告
UseDirectoryBrowser
和 UseStaticFiles
可能會導致洩漏祕密。 強烈建議您在生產環境中停用目錄瀏覽功能。 透過 UseStaticFiles
或 UseDirectoryBrowser
,仔細檢閱要啟用哪些目錄。 因為整個目錄和其子目錄都可供公開存取。 將檔案存放在專門公開提供的目錄,例如 <content_root>/wwwroot
。 將這些檔案與 MVC 檢視、Razor Pages、組態檔等區隔開來。
使用
UseDirectoryBrowser
、UseStaticFiles
和MapStaticAssets
公開內容的 URL 可能有區分大小寫,並受限於基礎檔案系統的字元限制。 例如,Windows 不區分大小寫,但 macOS 和 Linux 則區分大小寫。裝載於 IIS 中的 ASP.NET Core 應用程式會使用 ASP.NET Core 模組,將所有要求轉送給應用程式 (包括靜態檔案要求), 未使用 IIS 靜態檔案處理常式,而且沒有處理要求的機會。
請完成 IIS 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:
- 巡覽至 [模組] 功能。
- 選取清單中的 StaticFileModule。
- 按一下 [動作] 側邊欄中的 [移除]。
警告
如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。
- 請將程式碼檔案 (包括
.cs
和.cshtml
) 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。
藉由更新 IWebHostEnvironment.WebRootPath,提供 wwwroot 外部的檔案
將 IWebHostEnvironment.WebRootPath 設定為 wwwroot
以外的資料夾時:
- 在開發環境中,在
wwwroot
和更新的IWebHostEnvironment.WebRootPath
中找到的靜態資產會從wwwroot
提供。 - 在開發以外的任何環境中,會從更新的
IWebHostEnvironment.WebRootPath
資料夾提供重複的靜態資產。
請考慮使用空白 Web 範本建立的 Web 應用程式:
在
wwwroot
和wwwroot-custom
中包含Index.html
檔案。使用下列設定
WebRootPath = "wwwroot-custom"
之已更新的Program.cs
檔案: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
中重複的具名資產。將
Properties/launchSettings.json
中的"ASPNETCORE_ENVIRONMENT"
設定為"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();
其他資源
HTML、CSS、影像和 JavaScript 這類靜態檔案都是 ASP.NET Core 應用程式預設直接提供給用戶端的資產。
提供靜態檔案
靜態檔案會儲存在專案的 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.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
您可透過 Web 根目錄的相對路徑來存取靜態檔案。 例如,Web 應用程式專案範本在 wwwroot
資料夾內包含數個資料夾:
wwwroot
css
js
lib
請考慮建立 wwwroot/images 資料夾並新增 wwwroot/images/MyImage.jpg
檔案。 存取 images
資料夾中檔案的 URI 格式為 https://<hostname>/images/<image_file_name>
。 例如,https://localhost:5001/images/MyImage.jpg
在 Web 根目錄中提供檔案
預設的 Web 應用程式範本會在 Program.cs
中呼叫 UseStaticFiles 方法,以便提供靜態檔案:
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();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
無參數的 UseStaticFiles
方法多載會將 Web 根目錄中的檔案標示為可提供。 下列標記參考 wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
在上述標記中,並排字元 ~
會指向 Web 根目錄。
提供 Web 根目錄外的檔案
請考慮使用目錄階層,以提供位於 Web 根目錄外部的靜態檔案:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
透過設定靜態檔案中介軟體,可讓要求存取 red-rose.jpg
檔案,如下所示:
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(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
上述程式碼會透過 StaticFiles URI 區段公開 MyStaticFiles 目錄階層。 對 https://<hostname>/StaticFiles/images/red-rose.jpg
的要求提供 red-rose.jpg
檔案。
下列標記參考 MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
若要提供來自多個位置的檔案,請參閱提供來自多個位置的檔案。
設定 HTTP 回應標頭
StaticFileOptions 物件可用來設定 HTTP 回應標頭。 除了設定從 Web 根目錄提供靜態檔案,下列程式碼會設定 Cache-Control 標頭:
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();
app.MapRazorPages();
app.Run();
上述程式碼會在本機快取中公開提供靜態檔案,為期一週 (604800 秒)。
靜態檔案授權
ASP.NET Core 範本在呼叫 UseAuthorization 之前呼叫 UseStaticFiles。 大部分的應用程式都遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:
- 靜態檔案上不會執行授權檢查。
- 靜態檔案中介軟體所提供的靜態檔案 (例如
wwwroot
下的靜態檔案) 可公開存取。
若要根據授權提供靜態檔案:
- 將它們儲存在
wwwroot
之外。 - 在呼叫
UseAuthorization
之後,指定路徑,再呼叫UseStaticFiles
。 - 設定後援授權原則。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.MapRazorPages();
app.Run();
在上述程式碼中,後援授權原則會要求所有使用者都經過驗證。 指定其自己授權需求的控制器、Razor Pages 等端點,不會使用後援授權原則。 例如,使用 [AllowAnonymous]
或 [Authorize(PolicyName="MyPolicy")]
的 Razor Pages、控制器或動作方法,會使用套用的授權屬性,而不是後援授權原則。
RequireAuthenticatedUser 會將 DenyAnonymousAuthorizationRequirement 新增至目前的執行個體,這會強制使目前的使用者經驗證。
可公開存取 wwwroot
下的靜態資產,因為會在 UseAuthentication
之前呼叫預設的靜態檔案中介軟體 (app.UseStaticFiles();
)。 MyStaticFiles 資料夾中的靜態資產需要驗證。 範例程式碼會示範這一點。
根據授權提供檔案的替代方法是:
將它們儲存在
wwwroot
外部和可存取靜態檔案中介軟體的任何目錄。透過套用授權的動作方法來提供服務並傳回 FileResult 物件:
[Authorize] public class BannerImageModel : PageModel { private readonly IWebHostEnvironment _env; public BannerImageModel(IWebHostEnvironment env) => _env = env; public PhysicalFileResult OnGet() { var filePath = Path.Combine( _env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg"); return PhysicalFile(filePath, "image/jpeg"); } }
上述方法需要每個檔案一個頁面或端點。 下列程式碼會為已驗證使用者傳回檔案或上傳檔案:
app.MapGet("/files/{fileName}", IResult (string fileName) =>
{
var filePath = GetOrCreateFilePath(fileName);
if (File.Exists(filePath))
{
return TypedResults.PhysicalFile(filePath, fileDownloadName: $"{fileName}");
}
return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");
// IFormFile uses memory buffer for uploading. For handling large file use streaming instead.
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads#upload-large-files-with-streaming
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, HttpContext context) =>
{
// Don't rely on the file.FileName as it is only metadata that can be manipulated by the end-user
// Take a look at 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");
app.Run();
如需完整的範例,請參閱 StaticFileAuth GitHub 資料夾。
瀏覽目錄
「目錄瀏覽」允許列出指定目錄中的目錄清單。
基於安全考量,「目錄瀏覽」功能預設為停用。 如需詳細資訊,請參閱靜態檔案的安全性考量。
使用 AddDirectoryBrowser 和 UseDirectoryBrowser 啟用「目錄瀏覽」:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";
// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
上述程式碼可讓您使用 URL https://<hostname>/MyImages
與每個檔案和資料夾的連結,來進行 wwwroot/images 資料夾的目錄瀏覽:
AddDirectoryBrowser
新增服務,目錄瀏覽中介軟體需要 HtmlEncoder 等服務。 這些服務可能會由其他呼叫 (例如 AddRazorPages) 新增,但我們建議呼叫 AddDirectoryBrowser
以確保會在所有應用程式中新增服務。
提供預設文件
[設定預設頁面] 為訪客在站台上提供了起點。 若要從 wwwroot
提供預設檔案,而不需要要求 URL 包含檔案名稱,請呼叫 UseDefaultFiles 方法:
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.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
您必須在 UseStaticFiles
之前先呼叫 UseDefaultFiles
,才能提供預設的檔案。 UseDefaultFiles
是 URL 重寫器,其無法提供檔案。
使用 UseDefaultFiles
,要求在 wwwroot
資料夾中搜尋:
default.htm
default.html
index.htm
index.html
從清單中找到的第一個檔案,就像用包含檔案名稱的要求所提供。 瀏覽器 URL 仍會繼續反應要求的 URI。
下列程式碼會將預設檔案名稱變更為 mydefault.html
:
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 options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
預設文件的 UseFileServer
UseFileServer 結合 UseStaticFiles
、UseDefaultFiles
和 UseDirectoryBrowser
(選擇性) 的功能。
呼叫 app.UseFileServer
以便提供靜態檔案和預設檔案。 未啟用「目錄瀏覽」功能:
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.UseFileServer();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
下列程式碼可讓您提供靜態檔案、預設檔案和目錄瀏覽功能:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
請考慮下列目錄階層:
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
下列程式碼可讓您提供靜態檔案、預設檔案和 MyStaticFiles
的目錄瀏覽功能:
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
必須在 EnableDirectoryBrowsing
屬性值為 true
時呼叫 AddDirectoryBrowser。
使用上述檔案階層和程式碼時,URL 解析如下:
URI | 回應 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
如果 MyStaticFiles 目錄中沒有預設命名的檔案,則 https://<hostname>/StaticFiles
會傳回具有可點選連結的目錄清單:
UseDefaultFiles 和 UseDirectoryBrowser 會執行用戶端重新導向,從不含尾端 /
的目標 URI 重新導向至含尾端 /
的目標 URI。 例如,從 https://<hostname>/StaticFiles
到 https://<hostname>/StaticFiles/
。 除非使用 DefaultFilesOptions 的 RedirectToAppendTrailingSlash 選項,否則 StaticFiles 目錄內的相對 URL 若未含尾端斜線 (/
) 則會被視為無效。
FileExtensionContentTypeProvider
類別 FileExtensionContentTypeProvider 包含 Mappings
屬性,用作副檔名到 MIME 內容類型的對應。 在下列範例中,已有數個副檔名對應至已知的 MIME 類型。 已取代 .rtf 副檔名,並已移除 .mp4:
using Microsoft.AspNetCore.StaticFiles;
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();
// 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
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
請參閱 MIME 內容類型。
非標準的內容類型
靜態檔案中介軟體可識別近 400 種已知的檔案內容類型。 如果使用者要求具有未知檔案類型的檔案,則靜態檔案中介軟體會將該要求傳遞至管線中的下一個中介軟體。 如果沒有中介軟體處理要求,則會傳回「404 找不到」回應。 如果啟用目錄瀏覽功能,則會在目錄清單中顯示檔案的連結。
下列程式碼可讓您提供未知的類型,並會將未知的檔案轉譯為影像:
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(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
使用上述程式碼時,系統會以影像來回應具有未知內容類型的檔案要求。
警告
啟用 ServeUnknownFileTypes 會有安全性風險。 預設為停用,亦不建議您使用。 FileExtensionContentTypeProvider 可提供更安全的替代方法,來提供非標準副檔名的檔案。
提供來自多個位置的檔案
請考慮顯示 /MyStaticFiles/image3.png
檔案的下列 Razor 頁面:
@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(); // Serve files from wwwroot
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.UseStaticFiles();
注意
上述方法適用於 Razor Pages 和 MVC 應用程式。 如需適用於 Blazor Web App 的指導,請參閱 ASP.NET Core Blazor 靜態檔案。
靜態檔案的安全性考量
警告
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 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:
- 巡覽至 [模組] 功能。
- 選取清單中的 StaticFileModule。
- 按一下 [動作] 側邊欄中的 [移除]。
警告
如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。
- 請將程式碼檔案 (包括
.cs
和.cshtml
) 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。
藉由更新 IWebHostEnvironment.WebRootPath,提供 wwwroot 外部的檔案
將 IWebHostEnvironment.WebRootPath 設定為 wwwroot
以外的資料夾時:
- 在開發環境中,在
wwwroot
和更新的IWebHostEnvironment.WebRootPath
中找到的靜態資產會從wwwroot
提供。 - 在開發以外的任何環境中,會從更新的
IWebHostEnvironment.WebRootPath
資料夾提供重複的靜態資產。
請考慮使用空白 Web 範本建立的 Web 應用程式:
在
wwwroot
和wwwroot-custom
中包含Index.html
檔案。使用下列設定
WebRootPath = "wwwroot-custom"
之已更新的Program.cs
檔案: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.UseStaticFiles(); app.Run();
在上述程式碼中,對 /
的要求:
- 在開發環境中傳回
wwwroot/Index.html
- 在開發以外的任何環境中傳回
wwwroot-custom/Index.html
若要確保傳回來自 wwwroot-custom
的資產,請使用下列其中一種方法:
刪除
wwwroot
中重複的具名資產。將
Properties/launchSettings.json
中的"ASPNETCORE_ENVIRONMENT"
設定為"Development"
以外的任何值。在專案檔中設定
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
,以完全停用靜態 Web 資產。 警告,停用靜態 Web 資產會停用 Razor類別庫。將下列 JSON 新增至專案檔:
<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.UseStaticFiles();
app.Run();
其他資源
- 檢視或下載範例程式碼 \(英文\) (如何下載)
- 中介軟體
- ASP.NET Core 簡介
作者:Rick Anderson 與 Kirk Larkin
HTML、CSS、影像和 JavaScript 這類靜態檔案都是 ASP.NET Core 應用程式預設直接提供給用戶端的資產。
提供靜態檔案
靜態檔案會儲存在專案的 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.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
您可透過 Web 根目錄的相對路徑來存取靜態檔案。 例如,Web 應用程式專案範本在 wwwroot
資料夾內包含數個資料夾:
wwwroot
css
js
lib
請考慮建立 wwwroot/images 資料夾並新增 wwwroot/images/MyImage.jpg
檔案。 存取 images
資料夾中檔案的 URI 格式為 https://<hostname>/images/<image_file_name>
。 例如,https://localhost:5001/images/MyImage.jpg
在 Web 根目錄中提供檔案
預設的 Web 應用程式範本會在 Program.cs
中呼叫 UseStaticFiles 方法,以便提供靜態檔案:
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();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
無參數的 UseStaticFiles
方法多載會將 Web 根目錄中的檔案標示為可提供。 下列標記參考 wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
在上述標記中,並排字元 ~
會指向 Web 根目錄。
提供 Web 根目錄外的檔案
請考慮使用目錄階層,以提供位於 Web 根目錄外部的靜態檔案:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
透過設定靜態檔案中介軟體,可讓要求存取 red-rose.jpg
檔案,如下所示:
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(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
上述程式碼會透過 StaticFiles URI 區段公開 MyStaticFiles 目錄階層。 對 https://<hostname>/StaticFiles/images/red-rose.jpg
的要求提供 red-rose.jpg
檔案。
下列標記參考 MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
若要提供來自多個位置的檔案,請參閱提供來自多個位置的檔案。
設定 HTTP 回應標頭
StaticFileOptions 物件可用來設定 HTTP 回應標頭。 除了設定從 Web 根目錄提供靜態檔案,下列程式碼會設定 Cache-Control 標頭:
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();
app.MapRazorPages();
app.Run();
上述程式碼會在本機快取中公開提供靜態檔案,為期一週 (604800 秒)。
靜態檔案授權
ASP.NET Core 範本在呼叫 UseAuthorization 之前呼叫 UseStaticFiles。 大部分的應用程式都遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:
- 靜態檔案上不會執行授權檢查。
- 靜態檔案中介軟體所提供的靜態檔案 (例如
wwwroot
下的靜態檔案) 可公開存取。
若要根據授權提供靜態檔案:
- 將它們儲存在
wwwroot
之外。 - 在呼叫
UseAuthorization
之後,指定路徑,再呼叫UseStaticFiles
。 - 設定後援授權原則。
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.FileProviders;
using StaticFileAuth.Data;
var builder = WebApplication.CreateBuilder(args);
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();
builder.Services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.MapRazorPages();
app.Run();
在上述程式碼中,後援授權原則會要求所有使用者都經過驗證。 指定其自己授權需求的控制器、Razor Pages 等端點,不會使用後援授權原則。 例如,使用 [AllowAnonymous]
或 [Authorize(PolicyName="MyPolicy")]
的 Razor Pages、控制器或動作方法,會使用套用的授權屬性,而不是後援授權原則。
RequireAuthenticatedUser 會將 DenyAnonymousAuthorizationRequirement 新增至目前的執行個體,這會強制使目前的使用者經驗證。
可公開存取 wwwroot
下的靜態資產,因為會在 UseAuthentication
之前呼叫預設的靜態檔案中介軟體 (app.UseStaticFiles();
)。 MyStaticFiles 資料夾中的靜態資產需要驗證。 範例程式碼會示範這一點。
根據授權提供檔案的替代方法是:
- 將它們儲存在
wwwroot
外部和可存取靜態檔案中介軟體的任何目錄。 - 透過套用授權的動作方法來提供服務並傳回 FileResult 物件:
[Authorize]
public class BannerImageModel : PageModel
{
private readonly IWebHostEnvironment _env;
public BannerImageModel(IWebHostEnvironment env) =>
_env = env;
public PhysicalFileResult OnGet()
{
var filePath = Path.Combine(
_env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
}
瀏覽目錄
「目錄瀏覽」允許列出指定目錄中的目錄清單。
基於安全考量,「目錄瀏覽」功能預設為停用。 如需詳細資訊,請參閱靜態檔案的安全性考量。
使用 AddDirectoryBrowser 和 UseDirectoryBrowser 啟用「目錄瀏覽」:
using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
var fileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/MyImages";
// Enable displaying browser links.
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = requestPath
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
上述程式碼可讓您使用 URL https://<hostname>/MyImages
與每個檔案和資料夾的連結,來進行 wwwroot/images 資料夾的目錄瀏覽:
AddDirectoryBrowser
新增服務,目錄瀏覽中介軟體需要 HtmlEncoder 等服務。 這些服務可能會由其他呼叫 (例如 AddRazorPages) 新增,但我們建議呼叫 AddDirectoryBrowser
以確保會在所有應用程式中新增服務。
提供預設文件
[設定預設頁面] 為訪客在站台上提供了起點。 若要從 wwwroot
提供預設檔案,而不需要要求 URL 包含檔案名稱,請呼叫 UseDefaultFiles 方法:
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.UseDefaultFiles();
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
您必須在 UseStaticFiles
之前先呼叫 UseDefaultFiles
,才能提供預設的檔案。 UseDefaultFiles
是 URL 重寫器,其無法提供檔案。
使用 UseDefaultFiles
,要求在 wwwroot
資料夾中搜尋:
default.htm
default.html
index.htm
index.html
從清單中找到的第一個檔案,就像用包含檔案名稱的要求所提供。 瀏覽器 URL 仍會繼續反應要求的 URI。
下列程式碼會將預設檔案名稱變更為 mydefault.html
:
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 options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
預設文件的 UseFileServer
UseFileServer 結合 UseStaticFiles
、UseDefaultFiles
和 UseDirectoryBrowser
(選擇性) 的功能。
呼叫 app.UseFileServer
以便提供靜態檔案和預設檔案。 未啟用「目錄瀏覽」功能:
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.UseFileServer();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
下列程式碼可讓您提供靜態檔案、預設檔案和目錄瀏覽功能:
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
請考慮下列目錄階層:
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
下列程式碼可讓您提供靜態檔案、預設檔案和 MyStaticFiles
的目錄瀏覽功能:
using Microsoft.Extensions.FileProviders;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddControllersWithViews();
builder.Services.AddDirectoryBrowser();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(builder.Environment.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
必須在 EnableDirectoryBrowsing
屬性值為 true
時呼叫 AddDirectoryBrowser。
使用上述檔案階層和程式碼時,URL 解析如下:
URI | 回應 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
如果 MyStaticFiles 目錄中沒有預設命名的檔案,則 https://<hostname>/StaticFiles
會傳回具有可點選連結的目錄清單:
UseDefaultFiles 和 UseDirectoryBrowser 會執行用戶端重新導向,從不含尾端 /
的目標 URI 重新導向至含尾端 /
的目標 URI。 例如,從 https://<hostname>/StaticFiles
到 https://<hostname>/StaticFiles/
。 除非使用 DefaultFilesOptions 的 RedirectToAppendTrailingSlash 選項,否則 StaticFiles 目錄內的相對 URL 若未含尾端斜線 (/
) 則會被視為無效。
FileExtensionContentTypeProvider
類別 FileExtensionContentTypeProvider 包含 Mappings
屬性,用作副檔名到 MIME 內容類型的對應。 在下列範例中,已有數個副檔名對應至已知的 MIME 類型。 已取代 .rtf 副檔名,並已移除 .mp4:
using Microsoft.AspNetCore.StaticFiles;
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();
// 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
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
請參閱 MIME 內容類型。
非標準的內容類型
靜態檔案中介軟體可識別近 400 種已知的檔案內容類型。 如果使用者要求具有未知檔案類型的檔案,則靜態檔案中介軟體會將該要求傳遞至管線中的下一個中介軟體。 如果沒有中介軟體處理要求,則會傳回「404 找不到」回應。 如果啟用目錄瀏覽功能,則會在目錄清單中顯示檔案的連結。
下列程式碼可讓您提供未知的類型,並會將未知的檔案轉譯為影像:
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(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseAuthorization();
app.MapDefaultControllerRoute();
app.MapRazorPages();
app.Run();
使用上述程式碼時,系統會以影像來回應具有未知內容類型的檔案要求。
警告
啟用 ServeUnknownFileTypes 會有安全性風險。 預設為停用,亦不建議您使用。 FileExtensionContentTypeProvider 可提供更安全的替代方法,來提供非標準副檔名的檔案。
提供來自多個位置的檔案
請考慮顯示 /MyStaticFiles/image3.png
檔案的下列 Razor 頁面:
@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(); // Serve files from wwwroot
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.UseStaticFiles();
靜態檔案的安全性考量
警告
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 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:
- 巡覽至 [模組] 功能。
- 選取清單中的 StaticFileModule。
- 按一下 [動作] 側邊欄中的 [移除]。
警告
如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。
- 請將程式碼檔案 (包括
.cs
和.cshtml
) 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。
藉由更新 IWebHostEnvironment.WebRootPath,提供 wwwroot 外部的檔案
將 IWebHostEnvironment.WebRootPath 設定為 wwwroot
以外的資料夾時:
- 在開發環境中,在
wwwroot
和更新的IWebHostEnvironment.WebRootPath
中找到的靜態資產會從wwwroot
提供。 - 在開發以外的任何環境中,會從更新的
IWebHostEnvironment.WebRootPath
資料夾提供重複的靜態資產。
請考慮使用空白 Web 範本建立的 Web 應用程式:
在
wwwroot
和wwwroot-custom
中包含Index.html
檔案。使用下列設定
WebRootPath = "wwwroot-custom"
之已更新的Program.cs
檔案: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.UseStaticFiles(); app.Run();
在上述程式碼中,對 /
的要求:
- 在開發環境中傳回
wwwroot/Index.html
- 在開發以外的任何環境中傳回
wwwroot-custom/Index.html
若要確保傳回來自 wwwroot-custom
的資產,請使用下列其中一種方法:
刪除
wwwroot
中重複的具名資產。將
Properties/launchSettings.json
中的"ASPNETCORE_ENVIRONMENT"
設定為"Development"
以外的任何值。在專案檔中設定
<StaticWebAssetsEnabled>false</StaticWebAssetsEnabled>
,以完全停用靜態 Web 資產。 警告,停用靜態 Web 資產會停用 Razor類別庫。將下列 JSON 新增至專案檔:
<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.UseStaticFiles();
app.Run();
其他資源
- 檢視或下載範例程式碼 \(英文\) (如何下載)
- 中介軟體
- ASP.NET Core 簡介
作者:Rick Anderson 與 Kirk Larkin
HTML、CSS、影像和 JavaScript 這類靜態檔案都是 ASP.NET Core 應用程式預設直接提供給用戶端的資產。
檢視或下載範例程式碼 \(英文\) (如何下載)
提供靜態檔案
靜態檔案會儲存在專案的 Web 根目錄中。 預設目錄為 {content root}/wwwroot
,但可以使用 UseWebRoot 方法加以變更。 如需詳細資訊,請參閱內容根目錄和 Web 根目錄。
CreateDefaultBuilder 方法可將內容根目錄設定為目前的目錄:
public class Program
{
public static void Main(string[] args)
{
CreateHostBuilder(args).Build().Run();
}
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup<Startup>();
});
}
上述程式碼是使用 Web 應用程式範本所建立。
您可透過 Web 根目錄的相對路徑來存取靜態檔案。 例如,Web 應用程式專案範本在 wwwroot
資料夾內包含數個資料夾:
wwwroot
css
js
lib
請考慮建立 wwwroot/images 資料夾並新增 wwwroot/images/MyImage.jpg
檔案。 存取 images
資料夾中檔案的 URI 格式為 https://<hostname>/images/<image_file_name>
。 例如,https://localhost:5001/images/MyImage.jpg
在 Web 根目錄中提供檔案
預設的 Web 應用程式範本會在 Startup.Configure
中呼叫 UseStaticFiles 方法,以便提供靜態檔案:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
無參數的 UseStaticFiles
方法多載會將 Web 根目錄中的檔案標示為可提供。 下列標記參考 wwwroot/images/MyImage.jpg
:
<img src="~/images/MyImage.jpg" class="img" alt="My image" />
在上述程式碼中,波狀符號 ~/
會指向 Web 根目錄。
提供 Web 根目錄外的檔案
請考慮使用目錄階層,以提供位於 Web 根目錄外部的靜態檔案:
wwwroot
css
images
js
MyStaticFiles
images
red-rose.jpg
透過設定靜態檔案中介軟體,可讓要求存取 red-rose.jpg
檔案,如下所示:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
上述程式碼會透過 StaticFiles URI 區段公開 MyStaticFiles 目錄階層。 對 https://<hostname>/StaticFiles/images/red-rose.jpg
的要求提供 red-rose.jpg
檔案。
下列標記參考 MyStaticFiles/images/red-rose.jpg
:
<img src="~/StaticFiles/images/red-rose.jpg" class="img" alt="A red rose" />
設定 HTTP 回應標頭
StaticFileOptions 物件可用來設定 HTTP 回應標頭。 除了設定從 Web 根目錄提供靜態檔案,下列程式碼會設定 Cache-Control
標頭:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
const string cacheMaxAge = "604800";
app.UseStaticFiles(new StaticFileOptions
{
OnPrepareResponse = ctx =>
{
// using Microsoft.AspNetCore.Http;
ctx.Context.Response.Headers.Append(
"Cache-Control", $"public, max-age={cacheMaxAge}");
}
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
上述程式碼會將最大存留期設定為 604800 秒 (7 天)。
靜態檔案授權
ASP.NET Core 範本在呼叫 UseAuthorization 之前呼叫 UseStaticFiles。 大部分的應用程式都遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:
- 靜態檔案上不會執行授權檢查。
- 靜態檔案中介軟體所提供的靜態檔案 (例如
wwwroot
下的靜態檔案) 可公開存取。
若要根據授權提供靜態檔案:
- 將它們儲存在
wwwroot
之外。 - 在呼叫
UseAuthorization
之後,指定路徑,再呼叫UseStaticFiles
。 - 設定後援授權原則。
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// wwwroot css, JavaScript, and images don't require authentication.
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles"
});
app.UseEndpoints(endpoints =>
{
endpoints.MapRazorPages();
});
}
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddRazorPages();
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
}
// Remaining code ommitted for brevity.
在上述程式碼中,後援授權原則會要求所有使用者都經過驗證。 指定其自己授權需求的控制器、Razor Pages 等端點,不會使用後援授權原則。 例如,使用 [AllowAnonymous]
或 [Authorize(PolicyName="MyPolicy")]
的 Razor Pages、控制器或動作方法,會使用套用的授權屬性,而不是後援授權原則。
RequireAuthenticatedUser 會將 DenyAnonymousAuthorizationRequirement 新增至目前的執行個體,這會強制使目前的使用者經驗證。
可公開存取 wwwroot
下的靜態資產,因為會在 UseAuthentication
之前呼叫預設的靜態檔案中介軟體 (app.UseStaticFiles();
)。 MyStaticFiles 資料夾中的靜態資產需要驗證。 範例程式碼會示範這一點。
根據授權提供檔案的替代方法是:
- 將它們儲存在
wwwroot
外部和可存取靜態檔案中介軟體的任何目錄。 - 透過套用授權的動作方法來提供服務並傳回 FileResult 物件:
[Authorize]
public IActionResult BannerImage()
{
var filePath = Path.Combine(
_env.ContentRootPath, "MyStaticFiles", "images", "red-rose.jpg");
return PhysicalFile(filePath, "image/jpeg");
}
瀏覽目錄
「目錄瀏覽」允許列出指定目錄中的目錄清單。
基於安全考量,「目錄瀏覽」功能預設為停用。 如需詳細資訊,請參閱靜態檔案的安全性考量。
使用下列方式啟用「目錄瀏覽」功能:
Startup.ConfigureServices
中的 AddDirectoryBrowser。Startup.Configure
中的 UseDirectoryBrowser。
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDirectoryBrowser();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
上述程式碼可讓您使用 URL https://<hostname>/MyImages
與每個檔案和資料夾的連結,來進行 wwwroot/images 資料夾的目錄瀏覽:
提供預設文件
[設定預設頁面] 為訪客在站台上提供了起點。 若要從 wwwroot
提供預設檔案,而不需要要求 URL 包含檔案名稱,請呼叫 UseDefaultFiles 方法:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
您必須在 UseStaticFiles
之前先呼叫 UseDefaultFiles
,才能提供預設的檔案。 UseDefaultFiles
是 URL 重寫器,其無法提供檔案。
使用 UseDefaultFiles
,要求在 wwwroot
資料夾中搜尋:
default.htm
default.html
index.htm
index.html
從清單中找到的第一個檔案,就像用包含檔案名稱的要求所提供。 瀏覽器 URL 仍會繼續反應要求的 URI。
下列程式碼會將預設檔案名稱變更為 mydefault.html
:
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
下列程式碼顯示具有上述程式碼的 Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("mydefault.html");
app.UseDefaultFiles(options);
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
預設文件的 UseFileServer
UseFileServer 結合 UseStaticFiles
、UseDefaultFiles
和 UseDirectoryBrowser
(選擇性) 的功能。
呼叫 app.UseFileServer
以便提供靜態檔案和預設檔案。 未啟用目錄瀏覽功能。 下列程式碼顯示具有 UseFileServer
的 Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
下列程式碼可讓您提供靜態檔案、預設檔案和目錄瀏覽功能:
app.UseFileServer(enableDirectoryBrowsing: true);
下列程式碼顯示具有上述程式碼的 Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseFileServer(enableDirectoryBrowsing: true);
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
請考慮下列目錄階層:
wwwroot
css
images
js
MyStaticFiles
images
MyImage.jpg
default.html
下列程式碼可讓您提供靜態檔案、預設檔案和 MyStaticFiles
的目錄瀏覽功能:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddDirectoryBrowser();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(); // For the wwwroot folder.
// using Microsoft.Extensions.FileProviders;
// using System.IO;
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.ContentRootPath, "MyStaticFiles")),
RequestPath = "/StaticFiles",
EnableDirectoryBrowsing = true
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
必須在 EnableDirectoryBrowsing
屬性值為 true
時呼叫 AddDirectoryBrowser。
使用檔案階層和上述程式碼時,URL 解析方式如下:
URI | 回應 |
---|---|
https://<hostname>/StaticFiles/images/MyImage.jpg |
MyStaticFiles/images/MyImage.jpg |
https://<hostname>/StaticFiles |
MyStaticFiles/default.html |
如果 MyStaticFiles 目錄中沒有預設命名的檔案,則 https://<hostname>/StaticFiles
會傳回具有可點選連結的目錄清單:
UseDefaultFiles 和 UseDirectoryBrowser 會執行用戶端重新導向,從不含尾端 /
的目標 URI 重新導向至含尾端 /
的目標 URI。 例如,從 https://<hostname>/StaticFiles
到 https://<hostname>/StaticFiles/
。 StaticFiles 目錄內的相對 URL 若未含尾端斜線 (/
) 則會被視為無效。
FileExtensionContentTypeProvider
類別 FileExtensionContentTypeProvider 包含 Mappings
屬性,用作副檔名到 MIME 內容類型的對應。 在下列範例中,已有數個副檔名對應至已知的 MIME 類型。 已取代 .rtf 副檔名,並已移除 .mp4:
// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages",
ContentTypeProvider = provider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
下列程式碼顯示具有上述程式碼的 Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
// using Microsoft.AspNetCore.StaticFiles;
// using Microsoft.Extensions.FileProviders;
// using System.IO;
// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos.
provider.Mappings.Remove(".mp4");
app.UseStaticFiles(new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages",
ContentTypeProvider = provider
});
app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(env.WebRootPath, "images")),
RequestPath = "/MyImages"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
請參閱 MIME 內容類型。
非標準的內容類型
靜態檔案中介軟體可識別近 400 種已知的檔案內容類型。 如果使用者要求具有未知檔案類型的檔案,則靜態檔案中介軟體會將該要求傳遞至管線中的下一個中介軟體。 如果沒有中介軟體處理要求,則會傳回「404 找不到」回應。 如果啟用目錄瀏覽功能,則會在目錄清單中顯示檔案的連結。
下列程式碼可讓您提供未知的類型,並會將未知的檔案轉譯為影像:
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
下列程式碼顯示具有上述程式碼的 Startup.Configure
:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "image/png"
});
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute();
});
}
使用上述程式碼時,系統會以影像來回應具有未知內容類型的檔案要求。
警告
啟用 ServeUnknownFileTypes 會有安全性風險。 預設為停用,亦不建議您使用。 FileExtensionContentTypeProvider 可提供更安全的替代方法,來提供非標準副檔名的檔案。
提供來自多個位置的檔案
UseStaticFiles
和 UseFileServer
預設為指向 wwwroot
的檔案提供者。 UseStaticFiles
和 UseFileServer
的其他執行個體可以提供給其他檔案提供者,以提供來自其他位置的檔案。 如需詳細資訊,請參閱這個 GitHub 問題。
靜態檔案的安全性考量
警告
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 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:
- 巡覽至 [模組] 功能。
- 選取清單中的 StaticFileModule。
- 按一下 [動作] 側邊欄中的 [移除]。
警告
如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。
- 請將程式碼檔案 (包括
.cs
和.cshtml
) 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。