什么是靜態文件?
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 .
完.