DefaultFilesMiddleware中間件的目的在於將目標目錄下的默認文件作為響應內容。我們知道,如果直接請求的就是這個默認文件,那麼前面介紹的StaticFileMiddleware中間件會將這個文件響應給客戶端。如果我們能夠將針對目錄的請求重定向到這個默認文件上,一切就迎刃而解了。實際上DefaultFilesMiddleware中間件的實現邏輯很簡單,它采用URL重寫的形式修改了當前請求的地址,即將針對目錄的URL修改成針對默認文件的URL。[本文已經同步到《ASP.NET Core框架揭秘》之中]
我們照例先來看看DefaultFilesMiddleware類型的定義。和其他兩個中間件類似,DefaultFilesMiddleware的構造就有一個IOptions<DefaultFilesOptions>類型的參數來指定相關的配置選項。由於DefaultFilesMiddleware中間件本質上依然體現了請求路徑與某個物理目錄的映射,所以DefaultFilesOptions依然派生於SharedOptionsBase。DefaultFilesOptions的DefaultNames屬性包含了預定義的默認文件名,我們可以看到它默認包含四個名稱(default.htm、default.html、index.htm或者index.html)。
1: public class DefaultFilesMiddleware
2: {
3: public DefaultFilesMiddleware(RequestDelegate next, IHostingEnvironment hostingEnv, IOptions<DefaultFilesOptions> options);
4: public Task Invoke(HttpContext context);
5: }
6:
7: public class DefaultFilesOptions : SharedOptionsBase
8: {
9: public IList<string> DefaultFileNames { get; set; }
10:
11: public DefaultFilesOptions() : this(new SharedOptions()){}
12: public DefaultFilesOptions(SharedOptions sharedOptions) : base(sharedOptions)
13: {
14: this.DefaultFileNames = new List<string> { "default.htm", "default.html", "index.htm", "index.html" };
15: }
16: }
我們同樣采用一種比較易於理解的形式重新定義這個DefaultFilesMiddleware類型以便於讀者朋友理解它具體采用的請求處理邏輯。如下面的代碼片段所示,DefaultFilesMiddleware和DirectoryBrowserMiddleware一樣會對請求做相應的驗證。如果當前目錄下存在某個默認文件,那麼它會將當前請求的URL修改成指向這個默認文件的URL。值得一提的是,DefaultFilesMiddleware中間件要求訪問目錄的請求路勁必須以字符“/”作為後綴,否則會在目前的路徑上添加這個後綴並針對最終的路徑發送一個重定向。
1: public class DefaultFilesMiddleware
2: {
3: private RequestDelegate _next;
4: private DefaultFilesOptions _options;
5:
6: public DefaultFilesMiddleware(RequestDelegate next, IHostingEnvironment env, IOptions<DefaultFilesOptions> options)
7: {
8: _next = next;
9: _options = options.Value;
10: _options.FileProvider = _options.FileProvider ?? env.WebRootFileProvider;
11: }
12:
13: public async Task Invoke(HttpContext context)
14: {
15: //只處理GET和HEAD請求
16: if (!new string[] { "GET", "HEAD" }.Contains(context.Request.Method,StringComparer.OrdinalIgnoreCase))
17: {
18: await _next(context);
19: return;
20: }
21:
22: //檢驗當前路徑是否與注冊的請求路徑相匹配
23: PathString path = new PathString(context.Request.Path.Value.TrimEnd('/') + "/");
24: PathString subpath;
25: if (!path.StartsWithSegments(_options.RequestPath, out subpath))
26: {
27: await _next(context);
28: return;
29: }
30:
31: //檢驗目標目錄是否存在
32: if (!_options.FileProvider.GetDirectoryContents(subpath).Exists)
33: {
34: await _next(context);
35: return;
36: }
37:
38: //檢驗當前目錄是否包含默認文件
39: foreach (var fileName in _options.DefaultFileNames)
40: {
41: if (_options.FileProvider.GetFileInfo($"{subpath}{fileName}").Exists)
42: {
43: //如果當前路徑不以"/"作為後綴,會響應一個針對“標准”URL的重定向
44: if (!context.Request.Path.Value.EndsWith("/"))
45: {
46: context.Response.StatusCode = 302;
47: context.Response.GetTypedHeaders().Location = new Uri(path.Value + context.Request.QueryString);
48: return;
49: }
50: //將針對目錄的URL更新為針對默認文件的URL
51: context.Request.Path = new PathString($"{context.Request.Path}{fileName}");
52: }
53: }
54: await _next(context);
55: }
56: }
正是因為DefaultFilesMiddleware中間件采用URL重寫的方式來響應默認文件,所以它最終依賴StaticFileMiddleware中間件來響應默認文件,所以針對後者的注冊時必須的。也正是這個原因,這個中間件需要優先注冊以確保URL重寫發生在StaticFileMiddleware響應文件之前。
ASP.NET Core應用針對靜態文件請求的處理[1]: 以Web的形式發布靜態文件
ASP.NET Core應用針對靜態文件請求的處理[2]: 條件請求與區間請求
ASP.NET Core應用針對靜態文件請求的處理[3]: StaticFileMiddleware中間件如何處理針對文件請求
ASP.NET Core應用針對靜態文件請求的處理[4]: DirectoryBrowserMiddleware中間件如何呈現目錄結構
ASP.NET Core應用針對靜態文件請求的處理[5]: DefaultFilesMiddleware中間件如何顯示默認頁面