ASP.NET Core 2.2 基礎知識(三) 靜態檔案
什麼是靜態檔案?
HTML,CSS,JS,圖片等都叫做靜態檔案.
要想提供靜態檔案給客戶端,需要註冊靜態檔案中介軟體.
我們先分別新增一個 WebAPI 專案,一個 Razor 檢視專案,比較兩個專案的 Startup 類的 Configure 方法:
WebAPI專案:
Razor專案:
可以看出,Razor專案多了一行程式碼 app.UseStaticFiles(); (下面那一行先不管)
這行程式碼的作用就是註冊靜態檔案中介軟體.
UseStaticFiles() 方法的 xml 註釋是這樣寫的 : Enables static file serving for the current request path.為當前請求路徑提供靜態檔案服務.
之所以 WebAPI 專案沒有註冊靜態檔案中介軟體,是因為 WebAPI 的定義和 Razor,MVC 不一樣.
我們再來比較一下 WebAPI 專案和 Razor 專案:
(Pages 資料夾先不管)
可以看出,Razor 專案多了一個叫 wwwroot 的東西.別看它圖示是個球,其實它就是一個資料夾:
那麼問題來了,既然 Razor 專案提供了靜態檔案中介軟體,那這個 wwwroot 資料夾裡面的檔案怎麼訪問呢?他們的路徑是什麼呢?
比如,我們現在要訪問 wwwroot/css/site.css
當然,如果我們把 app.UseStaticFiles(); 註釋掉,就404了:
從上面的例子中,可以看出,我們訪問的是路徑是: https://localhost:44301/css/site.css ,而不是 https://localhost:44301/wwwroot/css/site.css
顯然,系統默認了 wwwroot 資料夾,那這個預設的路徑在哪裡可以看呢?
我們在 Pages 檔案下的 Index.cshtml 頁面中增加如下程式碼:(紅色標註)
上面那行表示給 env 變數注入一個 IHostingEnvironment 型別的例項.
頁面顯示如下:
現在問題又來了,如果想訪問 wwwroot 資料夾外的檔案,應該怎麼設定路徑呢?
我們先新增一個資料夾 images,放入兩張圖片:
在 Startup 類中加入如下程式碼(紅色標註):
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { ...other codes
app.UseStaticFiles();
//下面這個靜態檔案中介軟體的設定,只針對其設定的檔案路徑下的檔案生效,和上面預設的靜態檔案路徑 wwwroot 下的檔案訪問相互獨立. app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//設定檔案路徑(物理路徑) RequestPath = new PathString(@"/files"),//設定訪問路徑(虛擬路徑) OnPrepareResponse = context => { context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//設定快取 }, });
...other codes }
設定快取的程式碼是順帶寫的,僅僅表示有這個功能,跟設定路徑沒有關係.
請求自定義檔案路徑:
請求 wwwroot 資料夾下的檔案:
可以看到,響應中沒有快取設定了,這證明了兩者相互獨立.
除了可以設定檔案路徑,訪問路徑,快取外, StaticFileOptions 類還有3個屬性:
1.ContentTypeProvider 內容提供器
它的功能,直接看程式碼就明白了.
var fileProvider = new FileExtensionContentTypeProvider(); fileProvider.Mappings.Remove(".jpg");//移除對 ".jpg" 檔案的響應 fileProvider.Mappings[".laotie"] = "image/jpeg";//新增對 ".laotie" 檔案的響應析,響應格式為 "image/jpeg" //下面這個靜態檔案中介軟體的設定,只針對其設定的檔案路徑下的檔案生效,和上面預設的靜態檔案路徑 wwwroot 下的檔案訪問相互獨立. app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//設定檔案路徑(物理路徑) RequestPath = new PathString(@"/files"),//設定訪問路徑(虛擬路徑) OnPrepareResponse = context => { context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//設定快取 }, ContentTypeProvider = fileProvider,//設定檔案提供器 });
我們再次請求 : https://localhost:44301/files/1.jpg
請求 : https://localhost:44301/files/3.laotie
2.ServeUnknownFileTypes
3.DefaultContentType
這兩個屬性一起說.
ServeUnknownFileTypes 的 xml 註釋是這樣寫的 : If the file is not a recognized content-type should it be served?Default: false. 如果檔案不是被認可的型別,那麼它是否應該提供(給客戶端)?預設:不提供.
那麼哪些型別是認可的呢?太多了....截一小部分圖:(這都是些啥型別啊,好詭異.小弟表示沒見過)
如果 ServeUnknownFileTypes 設定為 true,則表示要提供(給客戶端),而且是採用 DefaultContentType 屬性設定的響應型別提供.
而 DefaultContentType 的 xml 註釋是這樣寫的 :
//The default content type for a request if the ContentTypeProvider cannot determine one. 如果 ContentTypeProvider 屬性設定的提供器不能選擇出一個認可的型別,則採用該屬性設定的響應型別.
//None is provided by default, so the client must determine the format themselves.如果該屬性沒有提供響應型別(即該屬性沒有值,為null),則交給客戶端來格式化它們.
測試如下:
我們將 上述程式碼中的 fileProvider.Mappings[".laotie"] = "image/jpeg" 註釋掉,註釋後的完整程式碼如下:
var fileProvider = new FileExtensionContentTypeProvider(); fileProvider.Mappings.Remove(".jpg");//移除對 ".jpg" 檔案的解析 //fileProvider.Mappings[".laotie"] = "image/jpeg";//新增對 ".laotie" 檔案的解析,解析方式為 "image/jpeg" //下面這個靜態檔案中介軟體的設定,只針對其設定的檔案路徑下的檔案生效,和上面預設的靜態檔案路徑 wwwroot 下的檔案訪問相互獨立. app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//設定檔案路徑(物理路徑) RequestPath = new PathString(@"/files"),//設定訪問路徑(虛擬路徑) OnPrepareResponse = context => { context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//設定快取 }, ContentTypeProvider = fileProvider,//設定檔案提供器 });
我們再次請求 https://localhost:44301/files/3.laotie , 結果 404,因為我們刪掉了對 ".老鐵" 檔案型別的認可,而 ServeUnknownFileTypes 預設值又為 false
當我們把 ServeUnknownFileTypes 屬性設定為 ture :
app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")),//設定檔案路徑(物理路徑) RequestPath = new PathString(@"/files"),//設定訪問路徑(虛擬路徑) OnPrepareResponse = context => { context.Context.Response.Headers.Append("Cache-Control", "public,max-age=600");//設定快取 }, ContentTypeProvider = fileProvider,//設定檔案提供器 ServeUnknownFileTypes = true, });
再次請求 https://localhost:44301/files/3.laotie ,則正常顯示出了內容(圖就不上了)
我以為:如果設定 DefaultContentType = "text/plain" ,那麼 3.laotie 應該不能正常訪問,但實際上還是可以訪問.有點不明白.希望高手解答一下.
跟檔案訪問相關的中介軟體,除了上面提到的靜態檔案中介軟體外,還有兩個:
1.預設檔案中介軟體 app.UseDefaultFiles()
預設檔案中介軟體的預設檔案有4種:default.htm,default.html,index.htm,index.html
當然,我們也可以自定義.
下面的示例給出了預設中介軟體的相關功能.
//提供預設檔案 DefaultFilesOptions options = new DefaultFilesOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Default")), }; options.DefaultFileNames.Add("mydefault.html");//新增自定義的預設檔案 app.UseDefaultFiles(options); app.UseStaticFiles(); //使用靜態檔案中介軟體 app.UseStaticFiles(new StaticFileOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Default")) });
有兩點要特別注意:
1)必須在 UseStaticFiles 前呼叫 UseDefaultFiles .UseDefaultFiles 實際上用於重寫 URL,不提供檔案,真正提供檔案的依然是 UseStaticFiles .
2)兩個中介軟體的路徑必須設定一樣.理由就是第一條.
2.目錄瀏覽中介軟體 app.UseDirectoryBrowser()
該中介軟體的啟用方式,設定方式和靜態檔案中介軟體類似.
由於涉及安全考慮,微軟預設沒有啟動該中介軟體.
//啟用目錄瀏覽中介軟體 app.UseDirectoryBrowser(); app.UseDirectoryBrowser(new DirectoryBrowserOptions { FileProvider = new PhysicalFileProvider(Path.Combine(env.ContentRootPath, "Images")), RequestPath = new PathString(@"/files"), });
除了上述3種檔案相關的中介軟體外,系統提供了一個3合一的中介軟體:
//同時啟用預設的靜態檔案,預設檔案,靜態目錄瀏覽中介軟體,false 則不啟動靜態目錄瀏覽. app.UseFileServer(true);
處於安全考慮,要啟動目錄瀏覽中介軟體,需要傳入 true .
完.