在HTTP的語義中,重定向一般指的是服務端通過返回一個狀態(tài)碼為3XX的響應促使客戶端像另一個地址再次發(fā)起請求,本章將此稱為“客戶端重定向“。既然有客戶端重定向,自然就有服務端重定向,本章所謂的服務端重定向指的是在服務端通過改變請求路徑將請求導向另一個終結點。ASP.NET下的重定向是通過RewriteMiddleware中間件實現的。(本文提供的示例演示已經同步到《ASP.NET Core 6框架揭秘-實例演示版》)
[S2501]客戶端重定向 (源代碼)
[S2502]服務端重定向 (源代碼)
[S2503]采用IIS重寫規(guī)則實現重定向(源代碼)
[S2504]采用Apache重寫規(guī)則實現重定向(源代碼)
[S2505]基于HTTPS終結點的重定向(源代碼)
[S2501]客戶端重定向
我們可以為RewriteMiddleware中間件定義客戶端重定向規(guī)則使之返回一個Location報頭指向重定向地址的3XX響應??蛻舳耍ū热鐬g覽器)在接收到這樣的響應后會根據狀態(tài)碼約定的語義向重定向地址重新發(fā)起請求,我們將這種由客戶端對新的地址重新請求的方式稱為“客戶端重定向”。
下面演示的這個例子會將請求路徑以“foo/**”為前綴的請求重定向到新的路徑“/bar/**”。如代碼片段所示,我們通過調用UseRewriter擴展方法注冊了RewriteMiddleware中間件,該方法會將對應的RewriteOptions配置選項作為參數。我們直接調用構造函數創(chuàng)建的這個RewriteOptions對象,并調用其AddRedirect擴展方法添加了一個重定向規(guī)則,該方法定義了兩個參數,前者(“^/foo/(.*)”)代表參與重定向的原始路徑模式(正則表達式),后者(“baz/$1”)表示重定向目標地址模板,占位符“$1”表示在進行正則匹配時產生的首段捕獲內容(前綴“foo/”后面的部分)。請求的URL會作為響應的內容。
using Microsoft.AspNetCore.Rewrite; var app = WebApplication.Create(); var options = new RewriteOptions().AddRedirect("^foo/(.*)", "bar/$1"); app.UseRewriter(options); app.MapGet("/{**foobar}", (HttpRequest request) =>$"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}"); app.Run();
演示程序注冊了一個采用“/{**foobar}”路由模板的終結點,請求URL直接作為該終結點的響應內容。演示程序啟動之后,所有路徑以“/foo”為前綴的請求都會自動重定向到以“/bar”為前綴的地址。如果請求路徑被設置為“/foo/abc/123”,最終將會被重定向到圖1所示的“/bar/abc/123”路徑下。
圖1 客戶端重定向
整個過程涉及HTTP報文交換更能體現客戶端重定向的本質。如下所示的是整個過程涉及的兩次報文交換,我們可以看出服務端第一次返回的是狀態(tài)碼為302的響應,根據映射規(guī)則生成的重定向地址體現在Location報頭上。
GET http://localhost:5000/foo/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 302 Found Content-Length: 0 Date: Wed, 22 Sep 2021 13:34:17 GMT Server: Kestrel Location: /bar/abc/123
GET http://localhost:5000/bar/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 200 OK Date: Wed, 22 Sep 2021 13:34:17 GMT Server: Kestrel Content-Length: 33 http://localhost:5000/bar/abc/123
[S2502]服務端重定向
服務端重定向會在服務端通過重寫請求路徑的方式將請求重定向到新的終結點。對于前面演示的程序來說,我們只需要對它做簡單的修改就能切換到服務端重定向。如下面的代碼片段所示,在RewriteOptions對象被創(chuàng)建后,我們調用它的另一個AddRewrite擴展方法注冊了一條服務端重定向(URL重寫)規(guī)則,原始請求路徑的正則表達式和重定向路徑均保持不變。
using Microsoft.AspNetCore.Rewrite; var app = WebApplication.Create(); var options = new RewriteOptions(). .AddRewrite(regex: "^foo/(.*)", replacement: "bar/$1", skipRemainingRules: true); app.UseRewriter(options); app.MapGet("/{**foobar}", (HttpRequest request) => $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}"); app.Run();
圖2 服務端重定向
[S2503]采用IIS重寫規(guī)則實現重定向
重定向是絕大部分Web服務器(比如IIS、Apache和Nginx等)都會提供的功能,但是不同的服務器類型針對重定向規(guī)則具有不同的定義方式。IIS中的重定向被稱為“URL重寫”,具體的URL重寫規(guī)則采用XML格式進行定義,RewriteMiddleware中間件對它提供了原生的支持。我們將URL重寫規(guī)則以如下的方式定義在創(chuàng)建的rewrite.xml文件中,并將該文件保存在演示項目的根目錄下。
<rewrite> <rules> <rule name="foo"> <match url="^foo/(.*)" /> <action type="Redirect" url="baz/{R:1}" /> </rule> <rule name="bar"> <match url="^bar/(.*)" /> <action type="Rewrite" url="baz/{R:1}" /> </rule> </rules> </rewrite>
如上所示的XML文件定義了兩條指向目標地址“baz/{R:1}”的規(guī)則,這里的占位符“{R:1}”和前面定義的“$1”一樣,都表示針對初始請求路徑進行正則匹配時得到的第一段捕獲內容。兩條規(guī)則用來匹配原始路徑的正則表達式分別定義為“^foo/(.*)”和“^bar/(.*)”。它們采用的Action類型也不相同,前者為“Redirect”,表示客戶端重定向;后者為“Rewrite”,表示服務端重定向。
為了將采用XML文件定義的IIS重定向規(guī)則應用到演示程序中,我們對演示程序如下的修改。如代碼片段所示,在RewriteOptions對象被創(chuàng)建出來后,我們調用了它的AddIISUrlRewrite擴展方法添加了IIS URL重寫規(guī)則,該方法的兩個參數分別表示用來讀取規(guī)則文件的IFileProvider對象和規(guī)則文件針對該對象的路徑。由于規(guī)則文件存儲與項目根目錄下,這也是ASP.NET應用“內容根目錄”所在的位置,所以我們可以使用內容根目錄對應的IFileProvider對象。
using Microsoft.AspNetCore.Rewrite; var app = WebApplication.Create(); var options = new RewriteOptions().AddIISUrlRewrite(fileProvider: app.Environment.ContentRootFileProvider, filePath: "rewrite.xml"); app.UseRewriter(options); app.MapGet("/{**foobar}", (HttpRequest request) =>$"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}"); app.Run();
改動的程序啟動之后,我們針對添加的兩條重定向規(guī)則發(fā)送了對應的請求,它們采用的請求路徑分別為“/foo/abc/123”和“/bar/abc/123”。從圖3所示的輸出可以看出,這兩個請求均被重定向到相同的目標路徑“/baz/abc/123”。
圖3 IIS重定向規(guī)則
由于發(fā)送的兩個請求分別采用客戶端和服務端重定向方式導向新的地址,所以瀏覽器針對前者顯示的是重定向后的地址,對于后者則顯示原始的地址。整個過程涉及到的如下三次報文交互更能說明兩種重定向方式的差異,從報文內容我們可以進一步看出第一次采用的是響應狀態(tài)碼為301的永久重定向。
GET http://localhost:5000/foo/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 301 Moved Permanently Content-Length: 0 Date: Wed, 22 Sep 2021 23:26:02 GMT Server: Kestrel Location: /baz/abc/123
GET http://localhost:5000/baz/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 200 OK Date: Wed, 22 Sep 2021 23:26:02 GMT Server: Kestrel Content-Length: 33 http://localhost:5000/baz/abc/123
GET http://localhost:5000/bar/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 200 OK Date: Wed, 22 Sep 2021 23:26:26 GMT Server: Kestrel Content-Length: 33 http://localhost:5000/baz/abc/123
[S2504]采用Apache重寫規(guī)則實現重定向
上面我們演示了RewriteMiddleware中間件針對IIS重定向規(guī)則的支持,實際上該中間件還支持Apache的重定向模塊mod_rewriter所采用的重定向規(guī)則定義形式,我們照例來做一個簡單的演示。我們在項目根目錄下添加了一個名為rewrite.config的配置文件,并在其中定義了如下兩條重定向規(guī)則。
RewriteRule ^/foo/(.*) /baz/$1 [R=307] RewriteRule ^/bar/(.*) - [F]
上面第一條規(guī)則利用R這個Flag將路徑與正則表達式“^/foo/(.*)”相匹配的請求以重定向到新的路徑“/baz/$1”,具體采用的是針對狀態(tài)碼307的臨時客戶端重定向。對于其路徑與正則表達式“^/bar/(.*)”相匹配的請求,我們將它視為未經授權授權的請求,所以對應的規(guī)則采用F(Forbidden)這個Flag。為了讓演示程序采用上述這個配置文件定義的Apache重定向規(guī)則,我們只需要按照如下的方式調用RewriteOptions 對象的AddApacheModRewrite擴展方法就可以了。
using Microsoft.AspNetCore.Rewrite; var app = WebApplication.Create(); var options = new RewriteOptions().AddApacheModRewrite(fileProvider: app.Environment.ContentRootFileProvider, filePath: "rewrite.config"); app.UseRewriter(options); app.MapGet("/{**foobar}", (HttpRequest request) =>$"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}"); app.Run();
改動的程序啟動之后,我們針對添加的兩條重定向規(guī)則發(fā)送了對應的請求,它們采用的請求路徑分別為“/foo/abc/123”和“/bar/abc/123”。從圖4所示的輸出可以看出,第一個請求均被重定向到相同的目標路徑“/baz/abc/123”,第二個請求返回一個狀態(tài)碼為403的響應。
圖4Apache mod-_rewrite重定向規(guī)則
如下所示的是整個過程涉及到的三次報文交換。我們可以看出第一次請求得到的響應狀態(tài)碼正式我們在規(guī)則中顯式設置的307。第二個請求由于被視為權限不足,服務端直接返回一個狀態(tài)為“403 Forbidden”的響應。
GET http://localhost:5000/foo/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 307 Temporary Redirect Content-Length: 0 Date: Wed, 22 Sep 2021 23:56:26 GMT Server: Kestrel Location: /baz/abc/123
GET http://localhost:5000/baz/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 200 OK Date: Wed, 22 Sep 2021 23:56:26 GMT Server: Kestrel Content-Length: 33
GET http://localhost:5000/bar/abc/123 HTTP/1.1 Host: localhost:5000 HTTP/1.1 403 Forbidden Content-Length: 0 Date: Wed, 22 Sep 2021 23:56:33 GMT Server: Kestrel
[S2505]基于HTTPS終結點的重定向
將針對HTTP請求重定向到對應HTTPS終結點是一種常見的重定向場景。如下所示的演示針對路徑“/foo”和“/bar”注冊了兩個終結點,它們均由注冊的兩個中間件構建的RequestDelegate委托作為處理器,其中一個就是調用UseRewriter擴展方法注冊的RewriteMiddleware中間件,另一個中間件則是通過調用Run擴展方法注冊的,后者依然將最終請求的URL作為響應的內容。
using Microsoft.AspNetCore.Rewrite; var app = WebApplication.Create(); app.MapGet("/foo", CreateHandler(app, 302)); app.MapGet("/bar", CreateHandler(app, 307)); app.Run(); static RequestDelegate CreateHandler(IEndpointRouteBuilder endpoints, int statusCode) { var app = endpoints.CreateApplicationBuilder(); app .UseRewriter(new RewriteOptions().AddRedirectToHttps(statusCode, 5001)) .Run(httpContext => { var request = httpContext.Request; var address = $"{request.Scheme}://{request.Host}{request.PathBase}{request.Path}"; return httpContext.Response.WriteAsync(address); }); return app.Build(); }
兩個終結點的處理器通過本地方法CreateHandler創(chuàng)建出來的。該方法調用當前WebApplication對象的CreateApplicationBuilder方法創(chuàng)建了一個新的IApplicationBuilder對象,并調用后者的UseRewriter擴展方法注冊了RewriteMiddleware中間件。我們?yōu)樵撝虚g件提供的HTTPS重定向規(guī)則是通過調用RewriteOptions對象的AddRedirectToHttps擴展方法定義的,該方法時指定了重定向響應采用的狀態(tài)碼(302和307)和HTTPS終結點采用的端口號。改動的程序啟動之后,針對兩個終結點的HTTP請求(“http://localhost:5000/foo”和“http://localhost:5000/bar”)均以圖5所示的形式被重定向到了對應的HTTPS終結點。
圖5 HTTPS重定向文章來源:http://www.zghlxwxcb.cn/news/detail-480725.html
整個過程涉及到如下四次報文交換,我們可以看出我們通過調用AddRedirectToHttps擴展方法定義的規(guī)則采用的是客戶端重定向。重定向響應采用了我們設置的狀態(tài)碼,分別是“302 Found”和“307 Temporary Redirect”。文章來源地址http://www.zghlxwxcb.cn/news/detail-480725.html
GET http://localhost:5000/foo HTTP/1.1 Host: localhost:5000 HTTP/1.1 302 Found Content-Length: 0 Date: Thu, 23 Sep 2021 12:10:51 GMT Server: Kestrel Location: https://localhost:5001/foo
GET https://localhost:5001/foo HTTP/1.1 Host: localhost:5001 HTTP/1.1 200 OK Date: Thu, 23 Sep 2021 12:10:51 GMT Server: Kestrel Content-Length: 26 https://localhost:5001/foo
GET http://localhost:5000/bar HTTP/1.1 Host: localhost:5000 HTTP/1.1 307 Temporary Redirect Content-Length: 0 Date: Thu, 23 Sep 2021 12:10:57 GMT Server: Kestrel Location: https://localhost:5001/bar
GET https://localhost:5001/bar HTTP/1.1 Host: localhost:5001 HTTP/1.1 200 OK Date: Thu, 23 Sep 2021 12:10:57 GMT Server: Kestrel Content-Length: 26 https://localhost:5001/bar
到了這里,關于ASP.NET Core 6框架揭秘實例演示[37]:重定向的N種實現方式的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!