【ASP.NET Core】如何隱藏響應頭中的 “Kestrel”
全宇宙人民都知道,ASP.NET Core 應用是不依賴服務器組件的,因此它可以獨立運行,一般是使用支持跨平臺的 Kestrel 服務器(當然,在 Windows 上還可以考慮用 HttpSys,但要以管理員身份運行)。
盡管 SDK 文檔中推薦我們用服務器組件來“反向”代理,但獨立運行也是允許的。當 Web 應用獨立運行的時候,客戶端發出請求後,在響應的 HTTP 消息中,會附上一個 Server 頭,其值就是 Kestrel。如下面的高清無碼無水印截圖所示。
看到了吧,Server = Kestrel。上面老周做了個小站,並且是獨立運行的,但我想隱藏那個 Kestrel 名字,想把它改為 Pig Platform。既然想到了,那就動手,這個其實很好辦的,只要在中間件的 HTTP 管道中插入一個自定義的中間件,修改一下 Server 頭就行了。
實現方法就是在 Startup 類的 Configure 方法中 Use 一下就好了。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } app.Use(async (context, next) => { context.Response.Headers["Server"] = "Bun Server 2098"; await next(); }); app.UseMvc(); }
因為代碼不多,就沒必要寫中間件類了,直接 Use 方法傳委托就OK了。代碼固然是全宇宙最簡單的,可是,你得註意順序,啥意思呢,比如我改為這樣。
app.Use(async (context, next) => { await next(); context.Response.Headers["Server"] = "Bun Server 2098"; });
這樣修改後會出錯,因為 next 直接進入下一個中間件,而這“下一個”中間件就可能是 MVC 了,這時候 HTTP 頭的集合被鎖定,變成只讀了,一修改就出錯。所以,要在進入下一個中間件之前把 Server 頭改掉。
故,這樣才不會出錯。
context.Response.Headers["Server"] = "Bun Server 2098"; await next();
如此處理後,當客戶端訪問時,Server 頭就變成這樣。
效果是做到了,可,這樣一來,咱們的 Startup.Configure 方法好像不夠簡潔。而且,這代碼太不夠逼格,嚴重不符合現在年輕人熱衷於裝逼的時代需求。
為了讓其適應一切以裝逼為核心的時代精神,我們可以使用 Starup Filter。
看名字你會猜到,是個過濾器,它的作用就是:能把中間件插入到 HTTP 消息管道的最前面,或者最後面。實現 Filter 的方法是實現 IStartupFilter 接口。這個接口只有一個方法。
Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next);
這個方法和 Startup 類中的 Configure 方法很像。參數和返回值都一個帶 IApplicationBuilder 參數的委托。方法的 next 參數是下一個要執行的 Configure 方法,可能是下一個 Startup Filter 的 Configure 方法,也可能是 Startup 類的 Configure 方法。返回值就是我們對當前的 Configure 方法的處理。
先看看我的實現。
public class MyStartupFilter : IStartupFilter { public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) { return app => { app.Use(async (context, _next) => { context.Response.Headers.Add("Server", "Big Server"); await _next(); }); next(app); }; } }
在這個項目中,除了運行庫內部的,外部實現的 Starup Filter 只有一個—— MyStartupFilter ,所以,在 Configure 方法中,參數 next 就是 Startup 類的 Configure 方法。因此,在這裏,你可以決定應用程序是否執行 Startup 類中的 Configure 方法。
上面代碼的意思就是:先為應用程序註冊我們自己的中間件(此處是委托),修改 Server HTTP 頭,然後再調用 Startup 類中 Configure 方法。如此就使得我們自定義的中間件代碼被入到整個 HTTP 消息管道的前面。
這時候,你可以把 Startup 類中剛剛寫的代碼刪掉了,使用 Configure 方法繼續保持簡潔。
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //app.Use(async (context, next) => //{ // context.Response.Headers["Server"] = "Bun Server 2098"; // await next(); //}); app.UseMvc(); }
那麽這個 Startup Filter 類怎麽用呢,好像沒有添加的相關 API 。其實,ASP.NET Core 有一個萬能法則——依賴註入。當你自己寫的任何擴展類型不知道怎麽使用時,你就統統放進 ServiceCollection 裏面就好了。於是,可以修改 Starup 類的 ConfigureServices 方法。
public void ConfigureServices(IServiceCollection services) { services.AddMvc().WithRazorPagesAtContentRoot().AddRazorPagesOptions(o=> { o.Conventions.AddPageRoute("/Main", ""); }); services.AddTransient<IStartupFilter, MyStartupFilter>(); }
ServiceCollection 有三種 Add 方法,用途一樣,不同的是對象實例的生命周期。
1、AddSingleton:活得最長,壽與天齊。整個應用程序中它只產生一個實例。
2、AddScoped:壽命稍短,它主要在同一次 HTTP 請求中有效,從收到 HTTP 請求時創建實例,請求結束後銷毀實例。
3、AddTransient:這個最短命,用的時候創建實例,用完就扔。
我們這個 Startup Filter 只在應用初始化時用一次,後續不再使用,所以用 AddTransient 方法添加就行了,整個應用中就用一次,沒必要占著位置不放。
此時,訪問服務器,也能將默認的 Kestrel 修改。
效果一樣。
好了,今天就扯到這裏,不算什麽高大上技巧。
【ASP.NET Core】如何隱藏響應頭中的 “Kestrel”