ASP.NET Core 中的靜態檔案

注意

這不是本文的最新版本。 若要切換至最新版本,請使用目錄頂端 ASP.NET Core版本選取器。

版本選取器

如果選取器在窄瀏覽器視窗中看不到,請擴大視窗,或選取垂直省略號 (⋮) >目錄

目錄選取器

作者:Rick Anderson

靜態檔案,例如 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範本在呼叫 之前呼叫 UseStaticFilesUseAuthorization 。 大部分的應用程式都會遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:

  • 靜態檔案上不會執行任何授權檢查。
  • 靜態檔案中介軟體所提供的靜態檔案,例如 底下的 wwwroot 靜態檔案可公開存取。

若要根據授權提供靜態檔案:

  • 將它們儲存在 wwwroot 外部。
  • 呼叫 UseStaticFiles ,在呼叫 UseAuthorization 之後指定路徑。
  • 設定 後援授權原則
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 頁面等端點不會使用後援授權原則。 例如, Razor 頁面、控制器或動作方法搭配 [AllowAnonymous] 使用 [Authorize(PolicyName="MyPolicy")] 已套用的授權屬性,而不是後援授權原則。

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 資料夾。

瀏覽目錄

瀏覽目錄允許在指定的目錄中列出目錄。

基於安全性考慮,預設會停用瀏覽目錄。 如需詳細資訊,請參閱 靜態檔案的安全性考慮

使用 和 UseDirectoryBrowser 啟用瀏覽目錄 AddDirectoryBrowser

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結合 、 UseDefaultFiles 和 的功能 UseStaticFiles ,並選擇性地 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();

AddDirectoryBrowser當屬性值為 trueEnableDirectoryBrowsing ,必須呼叫 。

使用上述檔案階層和程式碼,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>/StaticFileshttps://<hostname>/StaticFiles/ 。 除非 RedirectToAppendTrailingSlash 使用 選項 DefaultFilesOptions否則 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">

UseStaticFilesUseFileServer 預設為指向 的 wwwroot 檔案提供者。 和 UseFileServer 的其他實例 UseStaticFiles 可以與其他檔案提供者一起提供,以提供來自其他位置的檔案。 下列範例會呼叫 UseStaticFiles 兩次來提供 來自 和 MyStaticFileswwwroot 檔案:

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "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();

靜態檔案的安全性考慮

警告

UseDirectoryBrowserUseStaticFiles 可能會導致洩漏祕密。 強烈建議您在生產環境中停用目錄瀏覽功能。 透過 UseStaticFilesUseDirectoryBrowser,仔細檢閱要啟用哪些目錄。 因為整個目錄和其子目錄都可供公開存取。 儲存適合在專用目錄中提供給公用的檔案,例如 <content_root>/wwwroot 。 將這些檔案與 MVC 檢視、 Razor 頁面、組態檔等分開。

  • 使用 UseDirectoryBrowserUseStaticFiles 公開內容的 URL 可能有區分大小寫,並受限於基礎檔案系統的字元限制。 例如,Windows 不區分大小寫,但 macOS 和 Linux 則不區分大小寫。

  • 裝載於 IIS 中的 ASP.NET Core 應用程式會使用 ASP.NET Core 模組,將所有要求轉送給應用程式 (包括靜態檔案要求), 不會使用 IIS 靜態檔案處理常式,而且沒有機會處理要求。

  • 請完成 IIS 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:

    1. 巡覽至 [模組] 功能。
    2. 選取清單中的 StaticFileModule
    3. 按一下 [動作] 側邊欄中的 [移除]

警告

如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。

  • 將程式碼檔案,包括 .cs.cshtml 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。

藉由更新 IWebHostEnvironment.WebRootPath,在 wwwroot 外部提供檔案

當 設定為 以外的 wwwroot 資料夾時 IWebHostEnvironment.WebRootPath

  • 在開發環境中,可在 和 更新 IWebHostEnvironment.WebRootPath 中找到 wwwroot 的靜態資產會從 wwwroot 提供。
  • 在開發以外的任何環境中,會從更新 IWebHostEnvironment.WebRootPath 的資料夾提供重複的靜態資產。

請考慮使用空白 Web 範本建立的 Web 應用程式:

  • 在 和 wwwroot-custom 中包含 wwwroot 檔案 Index.html

  • 使用下列已更新 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.UseStaticFiles();
    
    app.Run();
    

在上述程式碼中,要求 : /

  • 在開發環境中傳回 wwwroot/Index.html
  • 在開發傳回以外的任何環境中 wwwroot-custom/Index.html

若要確保傳回來自 wwwroot-custom 的資產,請使用下列其中一種方法:

  • 刪除 中 wwwroot 重複的具名資產。

  • 將 設定 "ASPNETCORE_ENVIRONMENT"Properties/launchSettings.json 以外的 "Development" 任何值。

  • 在專案檔中設定 <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> ,以完全停用靜態 Web 資產。 警告,停用靜態 Web 資產會Razor 停用類別庫

  • 將下列 JS ON 新增至專案檔:

    <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();

其他資源

作者:Rick AndersonKirk 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範本在呼叫 之前呼叫 UseStaticFilesUseAuthorization 。 大部分的應用程式都會遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:

  • 靜態檔案上不會執行任何授權檢查。
  • 靜態檔案中介軟體所提供的靜態檔案,例如 底下的 wwwroot 靜態檔案可公開存取。

若要根據授權提供靜態檔案:

  • 將它們儲存在 wwwroot 外部。
  • 呼叫 UseStaticFiles ,在呼叫 UseAuthorization 之後指定路徑。
  • 設定 後援授權原則
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 頁面等端點不會使用後援授權原則。 例如, Razor 頁面、控制器或動作方法搭配 [AllowAnonymous] 使用 [Authorize(PolicyName="MyPolicy")] 已套用的授權屬性,而不是後援授權原則。

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

瀏覽目錄

瀏覽目錄允許在指定的目錄中列出目錄。

基於安全性考慮,預設會停用瀏覽目錄。 如需詳細資訊,請參閱 靜態檔案的安全性考慮

使用 和 UseDirectoryBrowser 啟用瀏覽目錄 AddDirectoryBrowser

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結合 、 UseDefaultFiles 和 的功能 UseStaticFiles ,並選擇性地 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();

AddDirectoryBrowser當屬性值為 trueEnableDirectoryBrowsing ,必須呼叫 。

使用上述檔案階層和程式碼,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>/StaticFileshttps://<hostname>/StaticFiles/ 。 除非 RedirectToAppendTrailingSlash 使用 選項 DefaultFilesOptions否則 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">

UseStaticFilesUseFileServer 預設為指向 的 wwwroot 檔案提供者。 和 UseFileServer 的其他實例 UseStaticFiles 可以與其他檔案提供者一起提供,以提供來自其他位置的檔案。 下列範例會呼叫 UseStaticFiles 兩次來提供 來自 和 MyStaticFileswwwroot 檔案:

app.UseStaticFiles(); // Serve files from wwwroot
app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "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();

靜態檔案的安全性考慮

警告

UseDirectoryBrowserUseStaticFiles 可能會導致洩漏祕密。 強烈建議您在生產環境中停用目錄瀏覽功能。 透過 UseStaticFilesUseDirectoryBrowser,仔細檢閱要啟用哪些目錄。 因為整個目錄和其子目錄都可供公開存取。 儲存適合在專用目錄中提供給公用的檔案,例如 <content_root>/wwwroot 。 將這些檔案與 MVC 檢視、 Razor 頁面、組態檔等分開。

  • 使用 UseDirectoryBrowserUseStaticFiles 公開內容的 URL 可能有區分大小寫,並受限於基礎檔案系統的字元限制。 例如,Windows 不區分大小寫,但 macOS 和 Linux 則不區分大小寫。

  • 裝載於 IIS 中的 ASP.NET Core 應用程式會使用 ASP.NET Core 模組,將所有要求轉送給應用程式 (包括靜態檔案要求), 不會使用 IIS 靜態檔案處理常式,而且沒有機會處理要求。

  • 請完成 IIS 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:

    1. 巡覽至 [模組] 功能。
    2. 選取清單中的 StaticFileModule
    3. 按一下 [動作] 側邊欄中的 [移除]

警告

如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。

  • 將程式碼檔案,包括 .cs.cshtml 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。

藉由更新 IWebHostEnvironment.WebRootPath,在 wwwroot 外部提供檔案

當 設定為 以外的 wwwroot 資料夾時 IWebHostEnvironment.WebRootPath

  • 在開發環境中,可在 和 更新 IWebHostEnvironment.WebRootPath 中找到 wwwroot 的靜態資產會從 wwwroot 提供。
  • 在開發以外的任何環境中,會從更新 IWebHostEnvironment.WebRootPath 的資料夾提供重複的靜態資產。

請考慮使用空白 Web 範本建立的 Web 應用程式:

  • 在 和 wwwroot-custom 中包含 wwwroot 檔案 Index.html

  • 使用下列已更新 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.UseStaticFiles();
    
    app.Run();
    

在上述程式碼中,要求 : /

  • 在開發環境中傳回 wwwroot/Index.html
  • 在開發傳回以外的任何環境中 wwwroot-custom/Index.html

若要確保傳回來自 的資產 wwwroot-custom ,請使用下列其中一種方法:

  • 刪除 中重複的 wwwroot 具名資產。

  • 將 設定 "ASPNETCORE_ENVIRONMENT"Properties/launchSettings.json 以外的 "Development" 任何值。

  • 在專案檔中設定 <StaticWebAssetsEnabled>false</StaticWebAssetsEnabled> ,完全停用靜態 Web 資產。 警告,停用靜態 Web 資產會Razor 停用類別庫

  • 將下列 JS ON 新增至專案檔:

    <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();

其他資源

作者:Rick AndersonKirk 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 應用程式範本會在 UseStaticFilesStartup.Configure 呼叫 方法,以便提供靜態檔案:

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" />

在上述程式碼中,tilde 字元 ~/ 會指向 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.jpgred-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範本會呼叫 UseStaticFilesUseAuthorization 。 大部分的應用程式都遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:

  • 靜態檔案上不會執行任何授權檢查。
  • 靜態檔案中介軟體所提供的靜態檔案,例如 下的 wwwroot 靜態檔案可公開存取。

若要根據授權提供靜態檔案:

  • 將它們儲存在 wwwroot 外部。
  • 呼叫 UseStaticFiles ,在呼叫 UseAuthorization 之後指定路徑。
  • 設定 後援授權原則
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 頁面等端點指定自己的授權需求不會使用後援授權原則。 例如, Razor 頁面、控制器或動作方法搭配 [AllowAnonymous] 或使用 [Authorize(PolicyName="MyPolicy")] 套用的授權屬性,而不是後援授權原則。

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

瀏覽目錄

瀏覽目錄允許指定目錄中的目錄清單。

基於安全性考慮,預設會停用瀏覽目錄。 如需詳細資訊,請參閱 靜態檔案的安全性考慮

使用啟用瀏覽目錄:

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 結合 UseStaticFilesUseDefaultFiles 和 的功能,並選擇性 UseDirectoryBrowser 地結合 。

呼叫 app.UseFileServer 以啟用靜態檔案和預設檔案的服務。 未啟用目錄瀏覽功能。 下列程式碼顯示 Startup.ConfigureUseFileServer

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

AddDirectoryBrowser當屬性值為 trueEnableDirectoryBrowsing ,必須呼叫 。

使用檔案階層和上述程式碼時,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>/StaticFileshttps://<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 可提供更安全的替代方法,來提供非標準副檔名的檔案。

從多個位置提供檔案

UseStaticFilesUseFileServer 預設為指向 的 wwwroot 檔案提供者。 和 UseFileServer 的其他實例 UseStaticFiles 可以與其他檔案提供者一起提供,以提供來自其他位置的檔案。 如需詳細資訊,請參閱這個 GitHub 問題 \(英文\)。

靜態檔案的安全性考慮

警告

UseDirectoryBrowserUseStaticFiles 可能會導致洩漏祕密。 強烈建議您在生產環境中停用目錄瀏覽功能。 透過 UseStaticFilesUseDirectoryBrowser,仔細檢閱要啟用哪些目錄。 因為整個目錄和其子目錄都可供公開存取。 儲存適合在專用目錄中提供給公用的檔案,例如 <content_root>/wwwroot 。 將這些檔案與 MVC 檢視、 Razor 頁面、組態檔等分開。

  • 使用 UseDirectoryBrowserUseStaticFiles 公開內容的 URL 可能有區分大小寫,並受限於基礎檔案系統的字元限制。 例如,Windows 不區分大小寫,但 macOS 和 Linux 則不區分大小寫。

  • 裝載於 IIS 中的 ASP.NET Core 應用程式會使用 ASP.NET Core 模組,將所有要求轉送給應用程式 (包括靜態檔案要求), 不會使用 IIS 靜態檔案處理常式,而且沒有機會處理要求。

  • 請完成 IIS 管理員中的下列步驟,以移除伺服器或網站層級的 IIS 靜態檔案處理常式:

    1. 巡覽至 [模組] 功能。
    2. 選取清單中的 StaticFileModule
    3. 按一下 [動作] 側邊欄中的 [移除]

警告

如果已啟用 IIS 靜態檔案處理常式,但是未正確設定 ASP.NET Core 模組,仍可提供靜態檔案。 舉例來說,未部署 web.config 檔案時可能會發生上述情況。

  • 將程式碼檔案,包括 .cs.cshtml 放在應用程式專案的 Web 根目錄之外。 如此一來,即會建立應用程式的用戶端內容與伺服器端程式碼之間的邏輯分隔。 這樣可以防止伺服器端程式碼外洩。

其他資源