asp.net core 系列之靜態檔案

yuan發表於2019-07-25

這篇講解asp.net core中的靜態檔案(大致翻譯於官網)。

靜態檔案,例如HTML,CSS, images和JavaScript. 要想直接被客戶端訪問,需要做一些配置。

一.Serve static files(提供靜態檔案服務)

靜態檔案儲存在專案的web root 目錄下預設的目錄是<content_root>/wwwroot,但可以通過UseWebRoot方法來改變預設目錄

更多可以檢視: See Content root and Web root for more information.

應用的web host 必須知道內容根目錄。

WebHost.CreateDefaultBuilder方法設定內容根目錄到當前目錄中

public class Program
{
    public static void Main(string[] args)
    {
        CreateWebHostBuilder(args).Build().Run();
    }

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

靜態檔案可以通過一個相對web root的路徑來訪問

例如,web application 專案模板在wwwroot資料夾下包含幾個資料夾:

  • wwwroot
    • css
    • images
    • js

到images子目錄中的檔案的URI格式為:http://<server_address>/images/<image_file_name> 。 例如

http://localhost:9189/images/banner3.svg.

如果是.NET Framework, 新增 Microsoft.AspNetCore.StaticFiles包到專案中。如果是.NET Core, Microsoft.AspNetCore.App包含這個包。

配置中介軟體來允許提供靜態檔案的服務

1.Serve files inside of web root(在web root中提供files服務)

在Startup.Configure中呼叫UseStaticFiles方法

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles();
}

這個無參的UseStaticFiles方法標誌著web root中的檔案可以提供服務。下面的標籤引用 wwwroot/images/banner1.svg:

<img src="~/images/banner1.svg" alt="ASP.NET" class="img-responsive" />

在上面的程式碼中,~/ 指向webroot,更多資訊:Web root.

像上面的程式碼,要使用web root下的檔案,需要直接指向到web root下的具體的檔案

2.Serve files outside of web root(在web root外提供檔案服務)

考慮下面的目錄層級,將在web root外面的MyStaticFiles提供檔案服務

通過配置靜態檔案中介軟體(the Static File Middleware),使請求可以取得banner1.svg檔案:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
        RequestPath = "/StaticFiles"
    });
}

在上面的程式碼中,MyStaticFiles目錄通過StaticFiles URI被暴露

一個 到http://<server_address>/StaticFiles/images/banner1.svg 的請求,可以得到banner1.svg檔案。

下面的標記引用MyStaticFiles/images/banner1.svg檔案:

<img src="~/StaticFiles/images/banner1.svg" alt="ASP.NET" class="img-responsive" />

3.Set HTTP response headers(設定HTTP響應頭)

StaticFileOptions 物件可以被用來設定HTTP response headers(HTTP 響應頭)

另外配置靜態檔案服務於web root, 下面的程式碼設定了Cache-Control 頭:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    var cachePeriod = env.IsDevelopment() ? "600" : "604800";
    app.UseStaticFiles(new StaticFileOptions
    {
        OnPrepareResponse = ctx =>
        {
            // Requires the following import:
            // using Microsoft.AspNetCore.Http;
            ctx.Context.Response.Headers.Append("Cache-Control", $"public, max-age={cachePeriod}");
        }
    });
}

HeaderDictionaryExtensions.Append方法存在於Microsoft.AspNetCore.Http包中。

這個檔案在開發環境可以快取10分鐘(600秒)。

二.Static file authorization(靜態檔案授權)

靜態檔案中介軟體不會提供授權檢查。任何被它提供的檔案服務,包括在wwwroot下的,都是公開可以訪問的。

要基於授權提供檔案服務

  • 把它們儲存在wwwroot外面 和 對於靜態檔案中介軟體可以到達的任意目錄
  • 通過認證的action方法提供它們。返回一個FileResult物件:
[Authorize]
public IActionResult BannerImage()
{
    var file = Path.Combine(Directory.GetCurrentDirectory(), 
                            "MyStaticFiles", "images", "banner1.svg");

    return PhysicalFile(file, "image/svg+xml");
}

三.Enable directory browsing(允許目錄瀏覽)

目錄瀏覽允許你的web應用上的使用者看見一個目錄列表,和指定目錄裡的檔案

目錄瀏覽因為安全原因預設是被禁用的。可以在Startup.Configure方法中呼叫UseDirectoryBrowser方法來允許目錄瀏覽

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });
}

通過在Startup.ConfigureServices中呼叫AddDirectoryBrowser方法來新增必要的服務:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDirectoryBrowser();
}

上面的程式碼允許 wwwroot/images目錄下的目錄瀏覽通過 http://<server_address>/MyImages

使用這個連結來到達每個檔案和目錄:

允許目錄瀏覽的一些安全風險,可以看 Considerations

注意下面示例中的兩個UseStaticFiles的呼叫。

第一個呼叫允許wwwroot資料夾提供靜態檔案。

第二個呼叫允許wwwroot/images資料夾使用目錄瀏覽,通過http://<server_address>/MyImages :

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseStaticFiles(new StaticFileOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });
}

四.Serve a default document(提供一個預設文件)

當訪問你的網站時,設定一個預設的home page頁面提供給瀏覽者一個合乎邏輯的起始頁(預設頁)(starting point)

要提供一個預設的不需要使用者詳細修飾的URI的頁面,需要在Startup.Configure中呼叫UseDefaultFiles方法

public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();
    app.UseStaticFiles();
}

重點:UseDefaultFiles 必須在UseStaticFiles之前被呼叫來提供預設檔案。UseDefaultFiles是一個URL重寫器,它不會真正提供檔案服務。允許Static File Middleware通過UseStaticFiles來提供服務。

使用UseDefaultFiles,請求一個資料夾搜尋:

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

列表中第一個被找到的檔案會提供服務,好像請求是被詳細修飾一樣。

下面的程式碼改變預設檔名為mydefault.html:

public void Configure(IApplicationBuilder app)
{
    // Serve my app-specific default file, if present.
    DefaultFilesOptions options = new DefaultFilesOptions();
    options.DefaultFileNames.Clear();
    options.DefaultFileNames.Add("mydefault.html");
    app.UseDefaultFiles(options);
    app.UseStaticFiles();
}

五.UseFileServer(使用檔案伺服器)

UseFileServer結合了UseStaticFiles,UseDefaultFiles,和UseDirectoryBrowser的功能

下面的程式碼允許提供靜態檔案服務和預設檔案。目錄瀏覽沒被允許

app.UseFileServer();

下面的程式碼是建立在無參過載上的,允許目錄瀏覽

app.UseFileServer(enableDirectoryBrowsing: true);

考慮下面的目錄層級:

下面的程式碼允許MyStaticFiles中的靜態檔案,預設檔案和目錄瀏覽:

public void Configure(IApplicationBuilder app)
{
    app.UseStaticFiles(); // For the wwwroot folder

    app.UseFileServer(new FileServerOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")),
        RequestPath = "/StaticFiles",
        EnableDirectoryBrowsing = true
    });
}

當EnableDirectoryBrowsing屬性值是true時,AddDirectoryBrowser必須被呼叫

public void ConfigureServices(IServiceCollection services)
{
    services.AddDirectoryBrowser();
}

使用檔案層級和之前的程式碼,URLs解析如下:

如果在MyStaticFiles目錄中,沒有預設名稱的檔案存在,http://<server_address>/StaticFiles

返回目錄列表中被點選的連結:

六.FileExtensionContentTypeProvider

FileExtensionContentTypeProvider類包含一個對映屬性,這個對映屬性提供一個file extensions 到MIME content types 的對映。下面的程式碼中,幾個檔案擴充套件(file extensions)被註冊為已知的MIME types。 .rtf extension被替換了,並且 .mp4 被移除了。

public void Configure(IApplicationBuilder app)
{
    // 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(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages",
        ContentTypeProvider = provider
    });

    app.UseDirectoryBrowser(new DirectoryBrowserOptions
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), "wwwroot", "images")),
        RequestPath = "/MyImages"
    });
}

更多:MIME content types 

七.Non-standard content types(非標準型別)

Static File Middleware 理解幾乎400個已知的檔案型別(file content types).

如果使用者請求一個未知的檔案型別,Static File Middleware 會傳遞這個請求到管道上的下一個中介軟體。

如果沒有中介軟體可以處理這個請求,一個404 Not Found 響應會被返回。

如果目錄瀏覽被允許,在目錄列表中,一個到這個檔案的連結會被展示。

下面的程式碼允許提供未知的型別,並且渲染未知的檔案為一個圖片:

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

使用上面的程式碼,一個對未知檔案型別的請求會作為一個圖片返回。

警告:允許ServeUnknownFileTypes是有安全風險的。它預設是被禁用的,並且這種用法不推薦使用。FileExtensionContentTypeProvider提供一個更安全的可選的方式來提供帶有non-standard extensions擴充套件的檔案。

Considerations(考慮)

  • 使用UseDirectoryBrowser和UseStaticFiles來暴露內容的URLs是適合於大小寫敏感並且在檔案系統下有字元限制。例如,Windows是大小寫敏感的,macOSLinux不是。
  • ASP.NET Core 應用部署在IIS上,使用ASP.NET Core Module 來傳送所有的請求到應用,包括靜態檔案請求。IIS靜態檔案處理器(IIS static file handler)沒有使用。它沒有機會處理請求在它們被這個模組處理之前。
  • 在IIS Manager中移除IIS static file handler的步驟,在伺服器或者網站層次:
    1. 導航到Modules功能
    2. 選擇列表中的StaticFileModule
    3. 點選刪除

警告:如果IIS檔案處理器被允許並且ASP.NET Core Module沒有被正確配置,靜態檔案會提供服務。這會發生,例如,如果web.config檔案沒有被部署。

  • 存放程式碼檔案(包括.cs.cshtml)在專案的web root的外面。應用的客戶端內容和服務端程式碼在邏輯上應該被分開建立,(app’s client-side content and server-based code).這可以預防服務端程式碼被洩露。

地址:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/static-files?view=aspnetcore-2.2

 

相關文章