ASP.NET Core 中文文檔 第三章 原理(3)靜態文件處理


原文:Working with Static Files
作者:Rick Anderson
翻譯:劉怡(AlexLEWIS)
校對:謝煬(kiler398)許登洋(Seay)孟帥洋(書緣)

靜態文件(static files),諸如 HTML、CSS、圖片和 JavaScript 之類的資源會被 ASP.NET Core 應用直接提供給客戶端。

查看或下載樣式代碼

章節:

靜態文件服務

靜態文件通常位於 web root<content-root>/wwwroot)文件夾下。更多有關 Content root 或 Web root 的信息請訪問 intro 。你通常會把項目的當前目錄設置為 Content root,這樣項目的 web root 就可以在開發階段被明確。

public static void Main(string[] args)
{
    var host = new WebHostBuilder()
        .UseKestrel()
        .UseContentRoot(Directory.GetCurrentDirectory()) //手工高亮
        .UseIISIntegration()
        .UseStartup<Startup>()
        .Build();

    host.Run();
}

靜態文件能夠被保存在網站根目錄下的任意文件夾內,並通過相對根的路徑來訪問。比方說,當你通過 Visual Studio 創建一個默認的 Web 應用程序項目,在 wwwroot 目錄下會多出幾個文件夾:cssimages 以及 js 文件夾。形如下例的 URL 能夠直接訪問 images 目錄下的圖片:

  • http://<app>/images/<imageFileName>
  • http://localhost:9189/images/banner3.svg

為了能夠啟用靜態文件服務,你必須配置中間件(middleware),把靜態文件中間件加入到管道內。靜態文件中間件能夠通過下述方法來配置:在你的項目中增加 Microsoft.AspNetCore.StaticFiles 包依賴,然后從 Startup.Configure 調用 UseStaticFiles 擴展方法:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseStaticFiles(); //手工高亮
}

app.UseStaticFiles(); 使得 web root(默認為 wwwroot)下的文件可以被訪問。隨后我將展示如何通過使用 UseStaticFiles 將其他目錄下的內容也向外提供服務。

你必須在 project.json 文件中包含 “Microsoft.AspNetCore.StaticFiles”。

注意
web root 的默認目錄是 wwwroot,但你可以通過 UseWebRoot 來設置 web root 。具體可參考 intro

假設你有一個有層次結構的項目,你希望其中靜態文件的位於 web root 的外部,比如:

  • wwwroot

    • css
    • images
    • ...
  • MyStaticFiles

    • test.png

對於訪問 test.png 的請求,可以如此配置靜態文件中間件:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseStaticFiles();

    app.UseStaticFiles(new StaticFileOptions()                                      //手工高亮
    {                                                                               //手工高亮
        FileProvider = new PhysicalFileProvider(                                    //手工高亮
            Path.Combine(Directory.GetCurrentDirectory(), @"MyStaticFiles")),       //手工高亮
        RequestPath = new PathString("/StaticFiles")                                //手工高亮
    });                                                                             //手工高亮
}

在請求 http://<app>/StaticFiles/test.png 時,就能訪問到 test.png 文件。

靜態文件授權

靜態文件模塊並 提供授權檢查。任何通過該模塊提供訪問的文件,包括位於 wwwroot 下的文件都是公開的。為了給文件提供授權:

  • 將文件保存在 wwwroot 之外並將目錄設置為可被靜態文件中間件訪問到,同時——
  • 通過一個控制器的 Action 來訪問它們,通過授權后返回 FileResult

允許直接瀏覽目錄

目錄瀏覽允許網站用戶看到指定目錄下的目錄和文件列表。基於安全考慮,默認情況下是禁用目錄訪問功能的(參考 注意事項 )。在 Startup.Configure 中調用 UseDirectoryBrowser 擴展方法可以開啟網絡應用目錄瀏覽:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseStaticFiles(); // For the wwwroot folder

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

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

並且通過從 Startup.ConfigureServices 調用 AddDirectoryBrowser 擴展方法來增加所需服務。

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

這段代碼允許在訪問 http://<app>/MyImages 時可瀏覽 wwwroot/images 文件夾的目錄,其中包括該文件夾下的每一個文件與文件夾:

dir-browse

查看關於開放訪問目錄時的安全隱患 注意事項 一節。

注意兩個 app.UseStaticFiles 調用。第一個調用請求 wwwroot 文件夾下的 CSS、圖片和 JavaScript,第二個調用通過 http://<app>/MyImages 請求瀏覽 wwwroot/images 文件夾的目錄

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseStaticFiles(); // For the wwwroot folder                                  //手工高亮

    app.UseStaticFiles(new StaticFileOptions()                                       //手工高亮
    {
        FileProvider = new PhysicalFileProvider(
            Path.Combine(Directory.GetCurrentDirectory(), @"wwwroot\images")),
        RequestPath = new PathString("/MyImages")
    });

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

默認文檔服務

設置默認首頁能給你的站點的每個訪問者提供一個起始頁。為使站點能提供默認頁,避免用戶輸入完整 URI,須在 Startup.Configure 中調用 UseDefaultFiles 擴展方法:

public void Configure(IApplicationBuilder app)
{
    app.UseDefaultFiles();                                                          //手工高亮
    app.UseStaticFiles();
}

注意
UseDefaultFiles 必須在 UseStaticFiles 之前調用。UseDefaultFiles 只是重寫了 URL,而不是真的提供了這樣一個文件。你必須開啟靜態文件中間件(UseStaticFiles)來提供這個文件。

通過 UseDefaultFiles,請求文件夾的時候將檢索以下文件:

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

上述列表中第一個被找到的文件將返回給用戶(作為該完整 URI 的請求的應答,而此時瀏覽器 URL 將繼續顯示用戶輸入的 URI)。

下述代碼展示如何將默認文件名改為 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 包含了 UseStaticFilesUseDefaultFilesUseDirectoryBrowser 的功能。

下面的代碼啟用了靜態文件和默認文件,但不允許直接訪問目錄:

app.UseFileServer();

下面的代碼啟用了靜態文件、默認文件和目錄瀏覽功能:

app.UseFileServer(enableDirectoryBrowsing: true);

查看直接提供目錄訪問時的安全風險注意事項。作為一個集合了 UseStaticFilesUseDefaultFilesUseDirectoryBrowser 方法於一體的方法,如果你希望提供 web root 之外存在的文件,你要實例化並配置一個 FileServerOptions 對象傳遞給 UseFileServer 的參數。比方說在你的應用中有如下層次的目錄:

  • wwwroot

    • css
    • images
    • ...
  • MyStaticFiles

    • test.png
    • default.html

使用上面這個層次結構的示例,你可能希望啟用靜態文件、默認文件以及瀏覽 MyStaticFiles 目錄。下面的代碼片段演示了調用一次 FileServerOptions 來完整實現這些功能:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseStaticFiles();

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

如果在你從 Startup.ConfigureServices 請求調用 AddDirectoryBrowser 擴展方法時將 enableDirectoryBrowsing 置為 true,那么:

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

使用的文件層次結構:

URI Response
http://<app>/StaticFiles/test.png StaticFiles/test.png
http://<app>/StaticFiles MyStaticFiles/default.html

如果在 MyStaticFiles 目錄下沒有默認命名的文件,則 http://<app>/StaticFiles 將返回目錄列表,其中包含可供點擊的鏈接:

db2

注意
UseDefaultFilesUseDirectoryBrowser 將會把末尾不帶斜杠的 URL http://<app>/StaticFiles 重新定向到 http://<app>/StaticFiles/ (末尾增加了一個斜杠)。如果末尾不帶斜杠,文檔內相對 URL 會出錯。

FileExtensionContentTypeProvider

FileExtensionContentTypeProvider 類內包含一個將文件擴展名映射到 MIME 內容類型的集合。在下面的例子中,多個文件擴展名注冊為已知的 MIME 類型,“.rtf”被替換,“.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 = new PathString("/MyImages"),
        ContentTypeProvider = provider                                                //手工高亮
    });

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

查看 MIME 內容類型

非標准的內容類型

ASP.NET 靜態文件中間件能夠支持超過 400 種已知文件內容類型。如果用戶請求一個未知的文件類型,靜態文件中間件將返回 HTTP 404(未找到)響應。如果啟用目錄瀏覽,該文件的鏈接將會被顯示,但 URI 會返回一個 HTTP 404 錯誤。

下方代碼把不能識別的類型和文件作為圖片處理。

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

根據上面的代碼,未知內容類型的文件請求將返回一張圖片。

警告
開啟 ServeUnknownFileTypes 存在安全風險,請打消這個念頭。 FileExtensionContentTypeProvider (下文將解釋)提供了更安全的非標准擴展替代。

注意事項

警告
UseDirectoryBrowserUseStaticFiles 可能會泄密。我們推薦你 不要 在生產環境開啟目錄瀏覽。要小心哪些被你開啟了 UseStaticFilesUseDirectoryBrowser 的目錄(使得其子目錄都可被訪問)。我們建議將公開內容放在諸如 <content root>/wwwroot 這樣的目錄中,遠離應用程序視圖、配置文件等。

  • 使用 UseDirectoryBrowserUseStaticFiles 暴露的文件的 URL 是否區分大小寫以及字符限制受制於底層文件系統。比方說 Windows 是不區分大小寫的,但 macOS 和 Linux 則區分大小寫。

  • 托管於 IIS 的 ASP.NET Core 應用程序使用 ASP.NET Core 模塊向應用程序轉發所有請求,包括靜態文件。IIS 靜態文件處理程序(IIS Static File Handler)不會被使用,因為在 ASP.NET Core 模塊處理之前它沒有任何機會來處理請求。

  • 以下步驟可移除 IIS 靜態文件處理程序(在服務器層級或網站層級上):

    • 導航到 模塊 功能
    • 從列表中選中 StaticFileModule
    • 操作 側邊欄中點擊 刪除

警告
如果 IIS 靜態文件處理程序開啟 並且 ASP.NET Core 模塊(ANCM)沒有被正確配置(比方說 web.config 沒有部署),(也能)將會提供靜態文件。

  • 代碼文件(包括 C# 和 Razor)應該放在應用程序項目的 web root (默認為 wwwroot)之外的地方。這將確保您創建的應用程序能明確隔離客戶端側和服務器側源代碼,此舉能防止服務器側的代碼被泄露。

擴展資源

返回目錄


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM