共用方式為


ASP.NET Core 中的靜態檔案

Note

這不是這篇文章的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本

Warning

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。

靜態檔案 (也稱為靜態資產) 是 ASP.NET Core 應用程式不會動態產生的檔案。 相反地,它們會根據要求直接提供給用戶端,例如 HTML、CSS、影像和 JavaScript 檔案。

如需新增或取代本文中指引的 Blazor 靜態檔案指引,請參閱 ASP.NET Core Blazor 靜態檔案

若要在 ASP.NET Core 中啟用靜態檔案處理,請呼叫 MapStaticAssets

預設情況下,靜態檔案儲存在專案的 Web 根 目錄中。 預設目錄是 {CONTENT ROOT}/wwwroot,其中 {CONTENT ROOT} 預留位置是應用程式的內容 根目錄。 只有 wwwroot 資料夾中的檔案是可定址的,因此您無需擔心程式碼的其餘部分。

只有具有特定副檔名對應至支援媒體類型的檔案才會被視為靜態網頁資產。

靜態 Web 資產會在建置時被發現,並透過內容指紋進行最佳化,以防止重複利用舊檔案。 資產也會 壓縮 ,以減少資產交付時間。

在執行階段,探索到的靜態 Web 資產會公開為套用 HTTP 標頭的端點,例如 快取標頭 和內容類型標頭。 資源只會提供一次,直到檔案變更或瀏覽器清除其快取為止。 ETagLast-ModifiedContent-Type 標頭已設定。 更新應用程式後,瀏覽器無法使用過時的資產。

靜態資產的傳遞是以 端點路由為基礎,因此它可與其他端點感知功能搭配使用,例如授權。 其設計目的是要處理所有 UI 架構,包括 Blazor、Razor Pages 和 MVC。

映射靜態資產提供下列優點:

  • 應用程式中所有資產的建置時間壓縮,包括 JavaScript (JS)和樣式表單,但不包括已壓縮的影像和字型資產。 GzipContent-Encoding: gz) 壓縮會在開發期間使用。 Gzip 和 BrotliContent-Encoding: br) 壓縮在發佈期間都會使用。
  • 使用每個檔案內容之 SHA-256 哈希的 Base64編碼字串,在建置時間 所有資產的指紋。 這可防止重複使用舊版的檔案,即使已快取舊檔案也一樣。 帶有指紋的資產會使用 immutable 指令來快取,這樣一來,直到資產變更為止,瀏覽器都不會再次請求該資產。 對於不支援 immutable 指示詞的瀏覽器,會新增 max-age 指示詞
    • 即使一個資產沒有經過指紋處理,也會為每個靜態資產生成基於內容的 ETags,並使用檔案的指紋哈希作為 ETag 值。 這可確保瀏覽器只有在內容變更時才會下載檔案(或檔案第一次下載)。
    • 在內部,架構會將實體資產對應至其指紋,讓應用程式能夠:
      • 尋找自動生成的資產,例如用於 Razor的 Blazor 的 元件範圍 CSS,以及在 JS中描述的 JS 資產。
      • 在頁面 <head> 內容中產生連結標籤,以預先載入資產。

Map Static Assets 不提供縮小化或其他檔案轉換功能。 縮小化通常是由自訂程式碼或 第三方工具來處理。

若要在 ASP.NET Core 中啟用靜態檔案處理,請呼叫 UseStaticFiles

預設情況下,靜態檔案儲存在專案的 Web 根 目錄中。 預設目錄是 {CONTENT ROOT}/wwwroot,其中 {CONTENT ROOT} 預留位置是應用程式的內容 根目錄。 只有 wwwroot 資料夾中的檔案是可定址的,因此您無需擔心程式碼的其餘部分。

在執行階段,靜態檔案中介軟體會在要求並套用資產修改和內容類型標頭時傳回靜態 Web 資產。 ETagLast-ModifiedContent-Type 標頭已設定。

靜態檔案中介軟體提供靜態檔案服務,當 UseStaticFiles 在應用程式的請求處理管道中呼叫時被應用程式使用。 檔案會從 或 IWebHostEnvironment.WebRootPathWebRootFileProvider指定的路徑提供,該路徑預設為 Web 根資料夾,通常是 wwwroot

您也可以從 參考的專案和套件提供靜態 Web 資產。

變更 Web 根目錄

如果要更改 Web 根目錄,請使用該 UseWebRoot 方法。 如需詳細資訊,請參閱 ASP.NET Core 基本概念概觀

防止將wwwroot中的檔案與專案檔中的<Content>專案項目一起發佈。 下列範例會防止在 wwwroot/local 及其子目錄中發佈內容:

<ItemGroup>
  <Content Update="wwwroot\local\**\*.*" CopyToPublishDirectory="Never" />
</ItemGroup>

CreateBuilder 方法可將內容根目錄設定為目前的目錄:

var builder = WebApplication.CreateBuilder(args);

CreateDefaultBuilder 方法可將內容根目錄設定為目前的目錄:

Host.CreateDefaultBuilder(args)

在要求處理管線中,在呼叫 UseHttpsRedirection 之後,呼叫應用程式的要求處理管線 MapStaticAssets,以啟用從應用程式的 Web 根目錄提供靜態檔案:

app.MapStaticAssets();

在要求處理管線中,在呼叫 UseHttpsRedirection 之後,呼叫應用程式的要求處理管線 UseStaticFiles,以啟用從應用程式的 Web 根目錄提供靜態檔案:

app.UseStaticFiles();

您可透過 Web 根目錄的相對路徑來存取靜態檔案。

若要存取影像,請造訪 wwwroot/images/favicon.png

  • 網址格式: https://{HOST}/images/{FILE NAME}
    • 佔位符是 {HOST} 主機。
    • {FILE NAME} 預留位置表示檔案名稱。
  • 範例
    • 絕對網址: https://localhost:5001/images/favicon.png
    • 根相對網址: images/favicon.png

在應用程式中Blazor,images/favicon.png從應用程式資料夾favicon.png載入圖示影像 (wwwroot/images):

<link rel="icon" type="image/png" href="images/favicon.png" />

在 Pages 和 MVC 應用程式中 Razor ,波浪號字元 ~ 指向網頁根目錄。 在下列範例中,~/images/favicon.png從應用程式的 favicon.png 資料夾中載入圖示影像 (wwwroot/images) :

<link rel="icon" type="image/png" href="~/images/favicon.png" />

中斷中間件管道

若要避免在比對靜態資產之後執行整個中介軟體管線,這是 UseStaticFiles 的行為,請在 ShortCircuit 上呼叫 MapStaticAssets。 立即呼叫 ShortCircuit 會執行端點並回傳回應,防止其他中間件執行靜態資產請求。

app.MapStaticAssets().ShortCircuit();

在開發期間管理靜態檔案快取

在開發環境中執行時,例如在 Visual Studio 即時重載 開發測試期間,框架會覆寫快取標頭,以防止瀏覽器快取靜態檔案。 這有助於確保在檔案變更時使用最新版本的檔案,避免出現過時內容的問題。 在生產環境中,設定了正確的快取標頭,允許瀏覽器如預期快取靜態資產。

若要停用此行為,請在開發環境的應用程式設定檔案 ()EnableStaticAssetsDevelopmentCaching 中設定trueappsettings.Development.json

Development 環境中的靜態檔案

在本機執行應用程式時,靜態Web資產只會在開發環境中啟用。 若要在本機開發和測試期間,為開發以外的其他環境(例如,預備環境)啟用靜態檔案,請呼叫 UseStaticWebAssetsWebApplicationBuilder

Warning

呼叫UseStaticWebAssets以獲取精確的環境,避免在生產環境中意外啟用此功能,因為此功能會從磁碟上的不同位置提供檔案,而不是從專案。 本節中的範例會使用 IsStaging 檢查暫存環境。

if (builder.Environment.IsStaging())
{
    builder.WebHost.UseStaticWebAssets();
}

使用IWebHostEnvironment.WebRootPath在 Web 根目錄之外提供檔案

IWebHostEnvironment.WebRootPath 設定為非 wwwroot 資料夾時,會顯示以下預設行為:

  • 在開發環境中,如果具有相同名稱的資產同時存在於 wwwroot 和指派給 wwwroot 的不同資料夾,則靜態資產會從 WebRootPath 提供。
  • 在開發以外的任何環境中,重複的靜態資產會從WebRootPath資料夾中載入提供。

假設從空白 Web 範本建立的 Web 應用程式:

  • Index.htmlwwwroot 中包含 wwwroot-custom 檔案。
  • Program檔案已更新以進行WebRootPath = "wwwroot-custom"配置設定。
var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    WebRootPath = "wwwroot-custom"
});

依預設,對 / 的請求:

  • 在開發環境中, wwwroot/Index.html 會傳回。
  • 在開發以外的任何環境中, wwwroot-custom/Index.html 都會被退回。

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

  • 刪除重複命名的資產於 wwwroot

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

  • 在應用程式的專案檔中將 <StaticWebAssetsEnabled> 設定為 false 以停用靜態 Web 資產。 警告: 停用靜態 Web 資產會停用Razor類別庫

  • 將下列 XML 新增至項目檔:

    <ItemGroup>
      <Content Remove="wwwroot\**" />
    </ItemGroup>
    

下列程式碼會將 WebRootPath 更新為非 Development 值(Staging),保證重複的內容是從 wwwroot-custom 而非 wwwroot 傳回:

var builder = WebApplication.CreateBuilder(new WebApplicationOptions
{
    Args = args,
    EnvironmentName = Environments.Staging,
    WebRootPath = "wwwroot-custom"
});

靜態檔案中間件

靜態檔案中介軟體會在特定靜態檔案案例中啟用靜態檔案服務,通常除了對應靜態資產端點路由慣例 ()MapStaticAssets 之外。

在應用程式的要求處理管線中呼叫 UseStaticFiles 時,靜態檔案中介軟體會包含在要求處理中,這通常是在新增映射靜態資產端點慣例(MapStaticAssets)之後。

映射靜態資產端點的慣例用於針對 .NET 9 或更新版本的應用程式。 靜態檔案中介軟體必須用於以 .NET 9 之前 .NET 版本為目標的應用程式中。

靜態檔案中介軟體雖提供靜態檔案,但其優化程度不及(Map Static Assets)端點慣例所能達到的層級。 僅依賴靜態檔案中介軟體時,無法使用對應“靜態資產地圖”端點慣例的建置時壓縮和指紋識別功能。

端點慣例已針對提供應用程式在執行階段所知道的資產進行了最佳化。 如果應用程式提供來自其他位置的資產,例如磁碟或內嵌資源,則應使用靜態檔案中介軟體。

靜態檔案中介軟體支援本文涵蓋的下列功能,但不支援對應靜態資產端點慣例:

使用UseStaticFiles在 Web 根目錄之外提供檔案

請考慮下列目錄階層,其中靜態檔案位於應用程式 Web 根 目錄外部的資料夾中,名為 ExtraStaticFiles

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

請求可以透過設定新的靜態檔案中介軟體實例來存取 red-rose.jpg

下列 API 的命名空間:

using Microsoft.Extensions.FileProviders;

在現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之後的要求處理管線中:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
    RequestPath = "/static-files"
});

在上述程式代碼中 ExtraStaticFiles ,目錄階層會透過 static-files URL區段公開。 向 https://{HOST}/StaticFiles/images/red-rose.jpg 發出的請求,其中 {HOST} 佔位元是主機,提供 red-rose.jpg 檔案。

下列標記參考 ExtraStaticFiles/images/red-rose.jpg

<img src="static-files/images/red-rose.jpg" alt="A red rose" />

在上述範例中,Pages 和 MVC 檢視 ()Razor 支援src="~/StaticFiles/images/red-rose.jpg"波浪號斜線表示法,但應用程式中的Razor元件不支援Blazor波浪號斜線表示法。

從多個位置提供檔案

本節中的指引適用於 Razor Pages 和 MVC 應用程式。 如需適用於 Blazor Web App 的指導,請參閱 ASP.NET Core Blazor 靜態檔案

請考慮下列顯示公司標誌的標記:

<img src="~/logo.png" asp-append-version="true" alt="Company logo">

開發人員打算使用 影像標籤協助程式 來附加版本,並從自訂位置(名為 ExtraStaticFiles的資料夾)提供檔案。

下列範例會呼叫 MapStaticAssets 以提供來自 wwwroot 的檔案,以及呼叫 UseStaticFiles 以提供來自 ExtraStaticFiles 的檔案。

在現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之後的要求處理管線中:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});

下列範例會呼叫 UseStaticFiles 兩次,以同時提供來自 wwwrootExtraStaticFiles的檔案。

在現有呼叫 UseStaticFiles 之後的要求處理流程中:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"))
});

使用上述程式碼,會顯示檔案 ExtraStaticFiles/logo.png 。 不過,不會套用 影像標籤協助程式AppendVersion),因為標籤協助程式相依於 WebRootFileProvider,而該協助程式尚未更新以包含 ExtraStaticFiles 資料夾。

下列程式碼會使用WebRootFileProviderExtraStaticFiles更新以包含CompositeFileProvider資料夾。 這可讓影像標籤輔助器將版本套用至位於 ExtraStaticFiles 資料夾中的影像。

下列 API 的命名空間:

using Microsoft.Extensions.FileProviders;

在現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之前的要求處理管線中:

var webRootProvider = new PhysicalFileProvider(builder.Environment.WebRootPath);
var newPathProvider = new PhysicalFileProvider(
    Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles"));

var compositeProvider = new CompositeFileProvider(webRootProvider, newPathProvider);

app.Environment.WebRootFileProvider = compositeProvider;

UseStaticFilesUseFileServer 預設為指向 wwwroot 的檔案提供者。 UseStaticFilesUseFileServer 的其他執行個體可以提供給其他檔案提供者,以提供來自其他位置的檔案。 如需詳細資訊,請參閱 UseStaticFiles 與 UseFileServer for wwwroot 仍然需要搭配使用(dotnet/AspNetCore.Docs #15578)

設定 HTTP 回應標頭

用於 StaticFileOptions 設定 HTTP 回應標頭。 除了設定靜態檔案中介軟體以提供靜態檔案之外,下列程式碼還會將標頭設定Cache-Control為 604,800 秒 (一週)。

下列 API 的命名空間:

using Microsoft.AspNetCore.Http;

在現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之後的要求處理管線中:

app.UseStaticFiles(new StaticFileOptions
{
    OnPrepareResponse = ctx =>
    {
        ctx.Context.Response.Headers.Append(
            "Cache-Control", "public, max-age=604800");
    }
});

大量資產集合

當處理大型資產集合 (被視為大約 1,000 個或更多資產) 時,我們建議使用捆綁器來減少應用程式提供的最終資產數量,或 MapStaticAssetsUseStaticFiles結合。

MapStaticAssets 急切地載入資源建置程式期間擷取的預先計算中繼資料,以支援壓縮、快取和指紋識別。 這些功能是以應用程式使用更多記憶體為代價的。 對於經常存取的資產,通常值得付出代價。 對於不經常存取的資產,這種權衡可能不值得付出代價。

如果您不使用資源打包,我們建議您將 MapStaticAssetsUseStaticFiles 結合。 下列範例示範此方法。

在專案檔案 .csproj 中,使用 StaticWebAssetEndpointExclusionPattern MSBuild 屬性來從 MapStaticAssets 的最終資訊清單中篩選端點。 排除的檔案由 UseStaticFiles 提供,不會受益於壓縮、快取和指紋識別。

設定 的值 StaticWebAssetEndpointExclusionPattern時,保留 $(StaticWebAssetEndpointExclusionPattern) 以保留架構的預設排除模式。 在分號分隔的清單中新增其他模式。

在下列範例中,排除選項會在資料夾中 lib/icons 新增靜態檔案,這代表假設的圖示批次:

<StaticWebAssetEndpointExclusionPattern>
  $(StaticWebAssetEndpointExclusionPattern);lib/icons/**
</StaticWebAssetEndpointExclusionPattern>

app.UseHttpsRedirection();檔案中經由HTTPS重新導向中介軟體(Program)處理後:

app.UseStaticFiles();

app.UseAuthorization();

app.MapStaticAssets();

靜態檔案授權

當應用程式採用 後援授權原則時,所有未明確指定授權原則的要求都需要授權,包括授權中介軟體處理要求之後的靜態檔案要求。 將 AllowAnonymousAttribute 套用到靜態檔案的端點建構器,以允許匿名存取靜態檔案:

app.MapStaticAssets().Add(endpointBuilder => 
    endpointBuilder.Metadata.Add(new AllowAnonymousAttribute()));

當應用程式採用 後援授權原則時,所有未明確指定授權原則的要求都需要授權,包括授權中介軟體處理要求之後的靜態檔案要求。 ASP.NET Core 範本允許在呼叫UseStaticFiles之前呼叫UseAuthorization靜態檔案,以匿名存取靜態檔案。 大部分的應用程式都遵循此模式。 在授權中介軟體之前呼叫靜態檔案中介軟體時:

  • 靜態檔案上不會執行授權檢查。
  • 靜態檔案中介軟體提供的靜態檔案,例如那些 Web 根目錄 (通常是 wwwroot),可公開存取。

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

  • 確認應用程式已將 後援授權原則 設定為需要已驗證的使用者。
  • 將靜態檔案儲存在應用程式的 Web 根目錄之外。
  • 呼叫 UseAuthorization之後,呼叫 UseStaticFiles,指定 Web 根目錄外部靜態檔案資料夾的路徑。

下列 API 的命名空間:

using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;

服務報名:

builder.Services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

呼叫 UseAuthorization 後的請求處理管線中:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "SecureStaticFiles")),
    RequestPath = "/static-files"
});

下列 API 的命名空間:

using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.FileProviders;

Startup.ConfigureServices 中:

services.AddAuthorization(options =>
{
    options.FallbackPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();
});

Startup.Configure 呼叫 UseAuthorization 後,

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.ContentRootPath, "SecureStaticFiles")),
    RequestPath = "/static-files"
});

在上述程式碼中,後援授權原則需要經過驗證的使用者。 指定自己授權需求的端點 (例如控制器和 Razor 頁面) 不會使用後援授權政策。 例如,具有 Razor 或 [AllowAnonymous] 的 Pages、控制器或動作方法會使用已應用的授權屬性,而不是後援授權原則。

RequireAuthenticatedUser 會將 DenyAnonymousAuthorizationRequirement 新增至目前的執行個體,這會確保目前的使用者已通過驗證。

儲存在應用程式 Web 根目錄中的靜態資產可公開存取,因為預設的靜態檔案中介軟體 (UseStaticFiles) 會在 之前呼叫 UseAuthorization。 資料夾中的 SecureStaticFiles 靜態資產需要驗證。

根據授權提供檔案的替代方法是:

  • 將檔案儲存在 Web 根目錄和靜態檔案中介軟體可存取的任何目錄之外。
  • 透過套用授權的動作方法提供檔案,並傳回物件 FileResult

從頁面 Razor ():Pages/BannerImage.cshtml.cs

public class BannerImageModel : PageModel
{
    private readonly IWebHostEnvironment _env;

    public BannerImageModel(IWebHostEnvironment env) => _env = env;

    public PhysicalFileResult OnGet()
    {
        var filePath = Path.Combine(
            _env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");

        return PhysicalFile(filePath, "image/jpeg");
    }
}

來自控制器(Controllers/HomeController.cs):

[Authorize]
public IActionResult BannerImage()
{
    var filePath = Path.Combine(
        _env.ContentRootPath, "SecureStaticFiles", "images", "red-rose.jpg");

    return PhysicalFile(filePath, "image/jpeg");
}

上述方法需要每個檔案一個頁面或端點。

下列路由端點範例會傳回已驗證使用者的檔案。

Program 檔案中:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});

...

app.MapGet("/files/{fileName}", IResult (string fileName) => 
{
    var filePath = GetOrCreateFilePath(fileName);

    if (File.Exists(filePath))
    {
        return TypedResults.PhysicalFile(filePath, fileName);
    }

    return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");

下列路由端點範例會上傳系統管理員角色 (“admin”) 中已驗證使用者的檔案。

Program 檔案中:

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});

...

// IFormFile uses memory buffer for uploading. For handling large 
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, 
    HttpContext context) =>
{
    // Don't rely on the value in 'file.FileName', as it's only metadata that can 
    // be manipulated by the end-user. Consider the 'Utilities.IsFileValid' method 
    // that takes an 'IFormFile' and validates its signature within the 
    // 'AllowedFileSignatures'.

    var fileSaveName = Guid.NewGuid().ToString("N") + 
        Path.GetExtension(file.FileName);
    await SaveFileWithCustomFileName(file, fileSaveName);

    context.Response.Headers.Append("Location", linker.GetPathByName(context, 
        "GetFileByName", new { fileName = fileSaveName}));

    return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");

Startup.ConfigureServices 中:

services.AddAuthorization(options =>
{
    options.AddPolicy("AuthenticatedUsers", b => b.RequireAuthenticatedUser());
});

Startup.Configure 中:

app.MapGet("/files/{fileName}", IResult (string fileName) => 
{
    var filePath = GetOrCreateFilePath(fileName);

    if (File.Exists(filePath))
    {
        return TypedResults.PhysicalFile(filePath, fileName);
    }

    return TypedResults.NotFound("No file found with the supplied file name");
})
.WithName("GetFileByName")
.RequireAuthorization("AuthenticatedUsers");

下列程式碼會上傳系統管理員角色 (“admin”) 中已驗證使用者的檔案。

Startup.ConfigureServices 中:

services.AddAuthorization(options =>
{
    options.AddPolicy("AdminsOnly", b => b.RequireRole("admin"));
});

Startup.Configure 中:

// IFormFile uses memory buffer for uploading. For handling large 
// files, use streaming instead. See the *File uploads* article
// in the ASP.NET Core documentation:
// https://learn.microsoft.com/aspnet/core/mvc/models/file-uploads
app.MapPost("/files", async (IFormFile file, LinkGenerator linker, 
    HttpContext context) =>
{
    // Don't rely on the value in 'file.FileName', as it's only metadata that can 
    // be manipulated by the end-user. Consider the 'Utilities.IsFileValid' method 
    // that takes an 'IFormFile' and validates its signature within the 
    // 'AllowedFileSignatures'.

    var fileSaveName = Guid.NewGuid().ToString("N") + 
        Path.GetExtension(file.FileName);
    await SaveFileWithCustomFileName(file, fileSaveName);

    context.Response.Headers.Append("Location", linker.GetPathByName(context, 
        "GetFileByName", new { fileName = fileSaveName}));

    return TypedResults.Ok("File Uploaded Successfully!");
})
.RequireAuthorization("AdminsOnly");

目錄瀏覽

「目錄瀏覽」允許列出指定目錄中的目錄清單。

基於安全考量,「目錄瀏覽」功能預設為停用。 如需詳細資訊,請參閱靜態檔案的安全性考量

使用下列 API 啟用目錄瀏覽:

在以下範例中:

  • images應用程式根目錄的資料夾包含用於目錄瀏覽的影像。
  • 瀏覽影像的要求路徑是 /DirectoryImages
  • 呼叫 UseStaticFiles 並設定 FileProviderStaticFileOptions,可顯示個別檔案的瀏覽器連結。

下列 API 的命名空間:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

服務報名:

builder.Services.AddDirectoryBrowser();

在現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之後的要求處理管線中:

var fileProvider = new PhysicalFileProvider(
    Path.Combine(builder.Environment.WebRootPath, "images"));
var requestPath = "/DirectoryImages";

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = fileProvider,
    RequestPath = requestPath
});

下列 API 的命名空間:

using Microsoft.Extensions.FileProviders;
using System.IO;

Startup.ConfigureServices 中:

services.AddDirectoryBrowser();

Startup.Configure中,於現有對UseStaticFiles的呼叫之後:

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/DirectoryImages"
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/DirectoryImages"
});

上述程式碼允許使用 URL wwwroot/images 瀏覽資料夾的目錄https://{HOST}/DirectoryImages,其中包含每個檔案和資料夾的連結,其中{HOST}預留位置是主機。

AddDirectoryBrowser 新增目錄瀏覽中間件所需的服務,包括 HtmlEncoder。 這些服務可能會由其他呼叫新增,例如AddRazorPages,但我們建議您呼叫AddDirectoryBrowser以確保服務已新增。

提供預設文件

[設定預設頁面] 為訪客在站台上提供了起點。 若要提供預設檔案wwwroot,而不需要要求 URL 包含檔案名稱,請呼叫UseDefaultFiles

UseDefaultFiles 是 URL 重寫器,其無法提供檔案。 在要求處理管線中的現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之前:

app.UseDefaultFiles();

使用 UseDefaultFiles,要求在 wwwroot 資料夾中搜尋:

  • default.htm
  • default.html
  • index.htm
  • index.html

從清單中找到的第一個檔案,會被當作請求中已包含該檔案的名稱來提供。 瀏覽器 URL 仍會繼續反應要求的 URI。

下列程式碼會將預設檔案名稱變更為 default-document.html

var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("default-document.html");
app.UseDefaultFiles(options);

結合靜態檔案、預設文件和目錄瀏覽

UseFileServer 結合 UseStaticFilesUseDefaultFilesUseDirectoryBrowser (選擇性) 的功能。

在現有呼叫 MapStaticAssets (.NET 9 或更新版本) 或 UseStaticFiles (.NET 8 或更早版本) 之後的要求處理管線中,呼叫 UseFileServer 以啟用靜態檔案和預設檔案的提供:

app.UseFileServer();

上述範例未啟用目錄瀏覽。

下列程式碼可啟用靜態檔案、預設檔案和目錄瀏覽的服務。

服務報名:

builder.Services.AddDirectoryBrowser();

在現有呼叫 UseStaticFiles 之後的要求處理流程中:

app.UseFileServer(enableDirectoryBrowsing: true);

Startup.ConfigureServices 中:

services.AddDirectoryBrowser();

Startup.Configure中,於現有對UseStaticFiles的呼叫之後:

app.UseFileServer(enableDirectoryBrowsing: true);

對於主機位址 (/),UseFileServer 會傳回預設的 HTML 文件,然後是預設的 Razor 頁面 (Pages/Index.cshtml)或預設的 MVC 檢視 (Home/Index.cshtml)。

請考慮下列目錄階層:

  • wwwroot
    • css
    • images
    • js
  • ExtraStaticFiles
    • images
      • logo.png
    • default.html

下列程式碼會啟用靜態檔案和預設檔案的提供功能,以及ExtraStaticFiles 的目錄瀏覽功能。

下列 API 的命名空間:

using Microsoft.Extensions.FileProviders;

服務報名:

builder.Services.AddDirectoryBrowser();

在現有呼叫 UseStaticFiles 之後的要求處理流程中:

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(builder.Environment.ContentRootPath, "ExtraStaticFiles")),
    RequestPath = "/static-files",
    EnableDirectoryBrowsing = true
});

下列 API 的命名空間:

using Microsoft.Extensions.FileProviders;
using System.IO;

Startup.ConfigureServices 中:

services.AddDirectoryBrowser();

Startup.Configure中,於現有對UseStaticFiles的呼叫之後:

app.UseFileServer(new FileServerOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.ContentRootPath, "ExtraStaticFiles")),
    RequestPath = "/static-files",
    EnableDirectoryBrowsing = true
});

必須在 AddDirectoryBrowser 屬性值為 EnableDirectoryBrowsing 時呼叫 true

使用上述檔案階層和程式碼,URL 會如下表所示解析 ( {HOST} 預留位置是主機)。

URI 回應檔案
https://{HOST}/static-files/images/logo.png ExtraStaticFiles/images/logo.png
https://{HOST}/static-files ExtraStaticFiles/default.html

如果目錄中 ExtraStaticFiles 沒有預設命名的檔案, https://{HOST}/static-files 則會傳回具有可點擊連結的目錄清單,其中 {HOST} 預留位置是主機。

UseDefaultFilesUseDirectoryBrowser 會執行用戶端重新導向,從不含尾端 / 的目標 URI 重新導向至含尾端 / 的目標 URI。 例如,從 https://{HOST}/static-files (無尾端 /) 到 https://{HOST}/static-files/ (包括尾端 /)。 目錄中的ExtraStaticFiles相對 URL 若無尾端斜線(/)則無效,除非使用RedirectToAppendTrailingSlashDefaultFilesOptions選項。

將副檔名對應至 MIME 類型

Note

如需適用於 Blazor 應用程式的指引,請參閱 ASP.NET 核心 Blazor 靜態檔案

FileExtensionContentTypeProvider.Mappings 來新增或修改副檔名至 MIME 內容類型的對應關係。 在下列範例中,數個副檔名會對應至已知的 MIME 類型。 擴充套件會被 .rtf 取代,並且 .mp4 將被移除:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;

...

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    ContentTypeProvider = provider
});

當您有數個靜態檔案選項要設定時,您也可以使用以下方式 StaticFileOptions設定提供者:

var provider = new FileExtensionContentTypeProvider();

...

builder.Services.Configure<StaticFileOptions>(options =>
{
    options.ContentTypeProvider = provider;
});

app.UseStaticFiles();

Startup.Configure 中:

using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.FileProviders;
using System.IO;

...

// Set up custom content types - associating file extension to MIME type
var provider = new FileExtensionContentTypeProvider();
// Add new mappings
provider.Mappings[".myapp"] = "application/x-msdownload";
provider.Mappings[".htm3"] = "text/html";
provider.Mappings[".image"] = "image/png";
// Replace an existing mapping
provider.Mappings[".rtf"] = "application/x-msdownload";
// Remove MP4 videos
provider.Mappings.Remove(".mp4");

app.UseStaticFiles(new StaticFileOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/images",
    ContentTypeProvider = provider
});

app.UseDirectoryBrowser(new DirectoryBrowserOptions
{
    FileProvider = new PhysicalFileProvider(
        Path.Combine(env.WebRootPath, "images")),
    RequestPath = "/images"
});

如需詳細資訊,請參閱 MIME 內容類型

非標準的內容類型

靜態檔案中介軟體可識別近 400 種已知的檔案內容類型。 如果使用者要求具有未知檔案類型的檔案,則靜態檔案中介軟體會將該要求傳遞至管線中的下一個中介軟體。 如果沒有中介軟體處理要求,則會傳回「404 找不到」回應。 如果啟用目錄瀏覽功能,則會在目錄清單中顯示檔案的連結。

下列程式碼會啟用提供未知的內容類型,並將未知檔案轉譯為影像:

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

使用上述程式碼時,系統會以影像來回應具有未知內容類型的檔案要求。

Warning

啟用 ServeUnknownFileTypes 會有安全性風險。 預設為停用,亦不建議您使用。 將副檔名對應至 MIME 類型,提供比提供具有非標準副檔名的檔案更安全的替代方案。

提供自訂靜態檔案資訊清單

如果staticAssetsManifestPathnull,那麼IHostEnvironment.ApplicationName會用來定位資訊清單。 或者,指定資訊清單檔案的完整路徑。 如果使用相對路徑,則框架會在AppContext.BaseDirectory中搜尋檔案。

靜態檔案的安全性考量

Warning

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

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

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

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

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

Warning

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

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

MSBuild 屬性

下列表格顯示靜態檔案相關的 MSBuild 屬性及其中繼資料描述。

房產 Description
EnableDefaultCompressedItems 啟用預設壓縮包含/排除模式。
CompressionIncludePatterns 使用分號分隔的檔案模式清單,以包含在壓縮中。
CompressionExcludePatterns 要從壓縮中排除的檔案模式的分號分隔清單。
EnableDefaultCompressionFormats 啟用預設壓縮格式(Gzip 和 Brotli)。
BuildCompressionFormats 在建置期間使用的壓縮格式。
PublishCompressionFormats 發佈期間要使用的壓縮格式。
DisableBuildCompression 在建置期間停用壓縮。
CompressDiscoveredAssetsDuringBuild 在建置期間壓縮探索到的資產。
BrotliCompressionLevel Brotli 演算法的壓縮層級。
StaticWebAssetBuildCompressAllAssets 在建置時壓縮所有資產,而不只是那些在建置過程中被發現或被計算的資產。
StaticWebAssetPublishCompressAllAssets 在發佈時壓縮所有資產,而不僅限於建置期間發現或計算的資產。
房產 Description
StaticWebAssetBasePath 資料庫中所有資產的基底URL路徑。
StaticWebAssetsFingerprintContent 啟用內容指紋識別以破壞快取。
StaticWebAssetFingerprintingEnabled 啟用靜態 Web 資產的指紋識別功能。
StaticWebAssetsCacheDefineStaticWebAssetsEnabled 啟用靜態 Web 資產定義的快取。
StaticWebAssetEndpointExclusionPattern 排除端點的模式。
項目群組 Description 後設資料
StaticWebAssetContentTypeMapping 將檔案模式對應至端點的內容類型和快取標頭。 PatternCache
StaticWebAssetFingerprintPattern 定義將指紋套用至靜態 Web 資產以進行快取破壞的模式。 PatternExpression

中繼資料描述:

  • Pattern:用於比對檔案的 glob 模式。 對於 StaticWebAssetContentTypeMapping,它會比對檔案以判斷其內容類型 (例如, *.js JavaScript 檔案)。 對於 StaticWebAssetFingerprintPattern,它會識別包含多種副檔名的檔案,這些檔案需要特殊的指紋處理(例如 *.lib.module.js)。

  • Cache:指定 Cache-Control 相符內容類型的標頭值。 這會控制瀏覽器快取行為(例如,max-age=3600, must-revalidate 用於媒體檔案)。

  • Expression:定義如何將指紋嵌入到檔案名稱中。 預設值為 #[.{FINGERPRINT}],在副檔名之前插入指紋({FINGERPRINT} 佔位符)。

下列範例將點陣圖檔案的模式(.bmp)對應到 image/bmp 內容類型,其中 {CACHE HEADER} 代表要用於非指紋端點的 Cache-Control 標頭:

<ItemGroup>
  <StaticWebAssetContentTypeMapping Include="image/bmp" Cache="{CACHE HEADER}" Pattern="*.bmp" />
</ItemGroup>

執行階段配置選項

下表說明執行階段組態選項。

組態金鑰 Description
ReloadStaticAssetsAtRuntime 啟用靜態資產在開發時的熱重新載入功能:提供已修改的 Web 根目錄 (wwwroot) 檔案(重新計算 ETag,如需則重新壓縮),而非使用建置時的資訊清單版本。 除非明確設定,否則預設為僅在提供組建資訊清單時啟用。
DisableStaticAssetNotFoundRuntimeFallback true時,會隱藏提供建置資訊清單中不存在的新新增檔案的後援端點。 當 false 不存在時,將進行檔案存在檢查的 {**path} 備援(GET/HEAD),記錄警告並使用計算得到的 ETag 提供檔案。
EnableStaticAssetsDevelopmentCaching true時,會保留資產描述元上的原始 Cache-Control 標頭。 當 false 缺失或不存在時,會重寫 Cache-Control 標頭為 no-cache,以避免在開發期間進行過度積極的用戶端快取。
EnableStaticAssetsDevelopmentIntegrity true 時,會保留資產描述子的完整性屬性。 當 false 存在或不存在時,會移除任何完整性屬性,以防止在開發過程中檔案變更時產生不匹配。

其他資源