.Net Core 中介軟體之靜態檔案(StaticFiles)
一、介紹
在介紹靜態檔案中介軟體之前,先介紹 ContentRoot和WebRoot概念。
ContentRoot:指web的專案的資料夾,包括bin和webroot資料夾。
WebRoot:一般指ContentRoot路徑下的wwwroot資料夾。
介紹這個兩個概念是因為靜態資原始檔一般存放在WebRoot路徑下,也就是wwwroot。下面為這兩個路徑的配置,如下所示:
public static void Main(string[] args) {var host = new WebHostBuilder() .UseKestrel() .UseStartup() .UseContentRoot(Directory.GetCurrentDirectory()) .UseWebRoot(Directory.GetCurrentDirectory() + @"wwwroot") .UseEnvironment(EnvironmentName.Development) .Build(); host.Run(); }
上面的程式碼將ContentRoot路徑和WebRoot路徑都配置了,其實只需配置ContentRoot路徑,WebRoot預設為ContentRoot路徑下的wwwroot資料夾路徑。
在瞭解靜態檔案中介軟體前,還需要了解HTTP中關於靜態檔案快取的機制。跟靜態檔案相關的HTTP頭部主要有Etag和If-None-Match。
下面為訪問靜態檔案伺服器端和客戶端的流程:
1、客戶端第一次向客戶端請求一個靜態檔案。
2、伺服器收到客戶端訪問靜態檔案的請求,伺服器端會根據靜態檔案最後的修改時間和檔案內容的長度生成一個Hash值,並將這個值放到請求頭ETag中。
3、客戶端第二次發起同一個請求時,因為之前請求過此檔案,所以本地會有快取。在請求時會在請求頭中加上If-Nono-Match,其值為伺服器返回的ETag的值。
4、伺服器端比對傳送的來的If-None-Match的值和本地計算的ETag的值是否相同。如果相同,返回304狀態碼,客戶端繼續使用本地快取。如果不相同,返回200狀態碼,客戶端重新解析伺服器返回的資料,不使用本地快取。
具體看下面例子。
二、簡單使用
2.1 最簡單的使用
最簡單的使用就是在Configure中加入下面一句話,然後將靜態檔案放到webRoot的路徑下,我沒有修改webRoot指定的路徑,所以就是wwwroot資料夾。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseStaticFiles(); app.UseMvc(); }
在wwwroot資料夾下放一個名稱為1.txt的測試文字,然後透過地址訪問。
這種有一個缺點,暴露這個檔案的路徑在wwwroot下。
2.2 指定請求地址
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { app.UseMvc(); app.UseStaticFiles(new StaticFileOptions() { FileProvider = new PhysicalFileProvider(@"C:UsersAdministratorDesktop"), RequestPath = new PathString("/Static") }); //app.UseStaticFiles("/Static"); }
這種指定了靜態檔案存放的路徑為:C:UsersAdministratorDesktop,不是使用預設的wwwroot路徑,就隱藏了檔案的真實路徑,並且需要在地址中加上static才能訪問。
當然也可以不指明靜態檔案的路徑,只寫請求路徑,如上面程式碼中的註釋的例子。這樣靜態檔案就必須儲存到WebRoot對應的目錄下了。如果WebRoot的目錄對應的是wwwroot,靜態檔案就放到wwwroot資料夾中。
下面透過例子看一下靜態檔案的快取,如果你想做這個例子,別忘記先清空快取。
(第一次請求)
(第二次請求 檔案相對第一次請求沒有修改的情況)
(第三次請求 檔案相對第一次請求有修改的情況)
三、原始碼分析
原始碼在,這個專案還包含有其他中介軟體。既然是中介軟體最重要的就是引數為HttpContext的Invoke方法了,因為每一個請求都要經過其處理,然後再交給下一個中介軟體處理。下面為處理流程。
public async Task Invoke(HttpContext context) { var fileContext = new StaticFileContext(context, _options, _matchUrl, _logger, _fileProvider, _contentTypeProvider); if (!fileContext.ValidateMethod())//靜態檔案的請求方式只能是Get或者Head { _logger.LogRequestMethodNotSupported(context.Request.Method); } //判斷請求的路徑和配置的請求路徑是否匹配。如請求路徑為 //配置為RequestPath = new PathString("/Static") //則匹配,並將檔案路徑賦值給StaticFileContext中點的_subPath else if (!fileContext.ValidatePath()) { _logger.LogPathMismatch(fileContext.SubPath); } //透過獲取要訪問檔案的副檔名,獲取此檔案對應的MIME型別, //如果找到檔案對應的MIME,返回True,並將MIME型別賦值給StaticFileContext中的_contextType //沒有找到返回False. else if (!fileContext.LookupContentType()) { _logger.LogFileTypeNotSupported(fileContext.SubPath); } //判斷訪問的檔案是否存在。 //如果存在返回True,並根據檔案的最後修改時間和檔案的長度,生成Hash值,並將值賦值給_etag,也就是相應頭中的Etag。 //如果不存在 返回False,進入下一個中介軟體中處理 else if (!fileContext.LookupFileInfo()) { _logger.LogFileNotFound(fileContext.SubPath); } else { fileContext.ComprehendRequestHeaders(); //根據StaticFileContext中的值,加上對應的相應頭,併傳送響應。具體呼叫方法在下面 switch (fileContext.GetPreconditionState()) { case StaticFileContext.PreconditionState.Unspecified: case StaticFileContext.PreconditionState.ShouldProcess: if (fileContext.IsHeadMethod) { await fileContext.SendStatusAsync(Constants.Status200Ok); return; } try { if (fileContext.IsRangeRequest) { await fileContext.SendRangeAsync(); return; } await fileContext.SendAsync(); _logger.LogFileServed(fileContext.SubPath, fileContext.PhysicalPath); return; } catch (FileNotFoundException) { context.Response.Clear(); } break; case StaticFileContext.PreconditionState.NotModified: _logger.LogPathNotModified(fileContext.SubPath); await fileContext.SendStatusAsync(Constants.Status304NotModified); return; case StaticFileContext.PreconditionState.PreconditionFailed: _logger.LogPreconditionFailed(fileContext.SubPath); await fileContext.SendStatusAsync(Constants.Status412PreconditionFailed); return; default: var exception = new NotImplementedException(fileContext.GetPreconditionState().ToString()); Debug.Fail(exception.ToString()); throw exception; } } //進入下一個中介軟體中處理 await _next(context); }
新增響應頭的方法:
public void ApplyResponseHeaders(int statusCode) { _response.StatusCode = statusCode; if (statusCode校驗檔案是否修改的方法:
public bool LookupFileInfo() { _fileInfo = _fileProvider.GetFileInfo(_subPath.Value); if (_fileInfo.Exists) { _length = _fileInfo.Length; DateTimeOffset last = _fileInfo.LastModified; _lastModified = new DateTimeOffset(last.Year, last.Month, last.Day, last.Hour, last.Minute, last.Second, last.Offset).ToUniversalTime(); //透過修改時間和檔案長度,得到ETag的值 long etagHash = _lastModified.ToFileTime() ^ _length; _etag = new EntityTagHeaderValue('"' + Convert.ToString(etagHash, 16) + '"'); } return _fileInfo.Exists; }原文出處:https://www.cnblogs.com/MicroHeart/p/9604214.html
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/2471/viewspace-2814026/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 15.ASP.NET Core 應用程式中的靜態檔案中介軟體ASP.NET
- 啟動靜態檔案中介軟體
- ASP .Net Core 中介軟體的使用(一):搭建靜態檔案伺服器/訪問指定檔案伺服器
- ASP.NET Core 1.0 靜態檔案、路由、自定義中介軟體、身份驗證簡介ASP.NET路由
- asp.net core 系列之靜態檔案ASP.NET
- Asp.Net Core入門之靜態檔案ASP.NET
- 重新整理 .net core 實踐篇—————靜態中介軟體[二十一]
- asp .net core 靜態檔案資源
- asp .net core 中介軟體
- Asp.Net Core入門之自定義中介軟體ASP.NET
- .NET Core基礎篇之:白話管道中介軟體
- ASP.NET Core 中介軟體基本用法ASP.NET
- .NET Core 自定義中介軟體 Middleware
- ASP.NET Core - 自定義中介軟體ASP.NET
- [譯]ASP.NET Core 2.0 中介軟體ASP.NET
- ASP.NET Core靜態檔案處理原始碼探究ASP.NET原始碼
- .NET Core單檔案釋出靜態編譯AOT CoreRT編譯
- Go語言中介軟體框架 Negroni 的靜態檔案處理原始碼分析Go框架原始碼
- Asp.Net Core基礎篇之:白話管道中介軟體ASP.NET
- ASP.NET Core 中介軟體(Middleware)(一)ASP.NET
- asp.net core mvc 管道之中介軟體ASP.NETMVC
- ASP.NET Core 中介軟體詳解及專案實戰ASP.NET
- c# .Net Core靜態檔案伺服器學習總結C#伺服器
- .net core Redis訊息佇列中介軟體【InitQ】Redis佇列
- .Net Core如何優雅的實現中介軟體
- ASP.NET Core中介軟體初始化探究ASP.NET
- ASP.NET Core - 請求管道與中介軟體ASP.NET
- 換個角度學習ASP.NET Core中介軟體ASP.NET
- ASP.NET Core中介軟體與HttpModule有何不同ASP.NETHTTP
- 一文說通Dotnet Core的中介軟體
- 重新整理 .net core 實踐篇—————中介軟體[十九]
- ASP.NET Core中的中介軟體及其工作原理ASP.NET
- 中介軟體之訊息中介軟體-pulsar
- 深入探究ASP.NET Core異常處理中介軟體ASP.NET
- ASP.NET Core 2.2 基礎知識(十)【中介軟體】ASP.NET
- .net core 一個避免跨站請求的中介軟體
- Asp-Net-Core開發筆記:使用NPM和gulp管理前端靜態檔案筆記NPM前端
- ASP.NET Core使用靜態檔案、目錄遊覽與MIME型別管理ASP.NET型別