溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

和淺析ASP.NET MVC中關(guān)于URL Rewrite的實(shí)現(xiàn)

發(fā)布時(shí)間:2021-11-24 09:32:51 來(lái)源:億速云 閱讀:145 作者:柒染 欄目:編程語(yǔ)言

這期內(nèi)容當(dāng)中小編將會(huì)給大家?guī)?lái)有關(guān)和淺析ASP.NET MVC中關(guān)于URL Rewrite的實(shí)現(xiàn),文章內(nèi)容豐富且以專(zhuān)業(yè)的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

現(xiàn)在我們就來(lái)看一個(gè)真實(shí)案例:在ASP.NET MVC中使用IIS級(jí)別的URL Rewrite。

在當(dāng)時(shí)的文章中我談到,URL Rewrite分有IIS級(jí)別和ASP.NET兩種級(jí)別,并且各有各的特點(diǎn)和限制。在ASP.NET MVC中我們常用的方式是ASP.NET級(jí)別的URL Routing,它的作用是從URL中捕獲數(shù)據(jù)并交給程序使用(當(dāng)然還有“構(gòu)造”的功能,稍候再談)。因此,在ASP.NET MVC中我們往往不需要使用ASP.NET級(jí)別的URL Rewrite。而如今使用IIS級(jí)別的URL Rewrite,也正是因?yàn)橛心承┨厥鈫?wèn)題無(wú)法回避才“不得已而為之”的。

以下涉及到的URL都以http://51programming.com為例,這個(gè)域名已經(jīng)被我泛解析為127.0.0.1,如果您需要的話可以用它來(lái)做實(shí)驗(yàn)。

在許多年前,一個(gè)URL的Path就是普通的路徑,而動(dòng)態(tài)的參數(shù),如查詢路徑,是通過(guò)Query String提供的,例如:

http://51programming.com/products?keywords=helloworld為了避免混淆,在這里我們先來(lái)澄清一些概念。什么是URL,什么是Path,而什么是QueryString。例如在上面的地址,這三者分別是:

URL:http://51programming.com/products?keywords=helloworld   Path:http://51programming.com/products   Query String:keywords=helloworld

后來(lái)SEO興起之后,有人說(shuō)這樣的“動(dòng)態(tài)地址”不利于搜索引擎中的權(quán)重優(yōu)化,因此建議把關(guān)鍵字作為Path的一部分。于是就出現(xiàn)了這樣的URL:

http://51programming.com/products/helloworld這么看來(lái)問(wèn)題并不大,但是您要知道,關(guān)鍵字往往是由用戶輸入的,可能會(huì)輸入特殊字符。例如,如果用戶輸入了“200%”作為關(guān)鍵字,則兩種形式下的URL就分別是:

如果您嘗試一下便可以知道,第一個(gè)URL可以正常訪問(wèn),而第二個(gè)URL便會(huì)引發(fā)Bad Request異常:

和淺析ASP.NET MVC中關(guān)于URL Rewrite的實(shí)現(xiàn)

這是因?yàn)閁RL的Path部分出現(xiàn)了特殊字符,而這種字符只能出現(xiàn)在Query String中。

看到這個(gè)畫(huà)面,您還意識(shí)到了什么信息?在定位問(wèn)題的原因,以及設(shè)法解決問(wèn)題的時(shí)候,首先要明確的是到底是哪里出現(xiàn)了問(wèn)題。例如看到這個(gè)畫(huà)面,您應(yīng)該清楚地意識(shí)到一點(diǎn):這是ASP.NET拋出的異常,換句話說(shuō),IIS并沒(méi)有把它當(dāng)作是非法的URL,它還是老老實(shí)實(shí)地將URL交給ASP.NET ISAPI處理。因此,我們便可以動(dòng)用IIS級(jí)別的URL Rewrite,在進(jìn)入ASP.NET執(zhí)行引擎之前,就把URL替換成可接受的形式:

RewriteRule  ^/products/([^\?]*)\?(.+)    /products?$2&keywords=$1     [I,L,U]

RewriteRule  ^/products/([^\?]*)          /products?keywords=$1     [I,L,U]***行應(yīng)對(duì)的是帶有Query String的情況,而第二行則是沒(méi)有Query String的情況。這里用到的組件是IIRF(Ionic's Isapi Rewrite Filter),這是一款開(kāi)源產(chǎn)品,一年半前的文章里我推薦的也是這個(gè),現(xiàn)在它已經(jīng)有了升級(jí)。它的功能便是在進(jìn)入ASP.NET ISAPI之前,就將URL重寫(xiě)為其他形式:

和淺析ASP.NET MVC中關(guān)于URL Rewrite的實(shí)現(xiàn)

原本在第3步會(huì)出現(xiàn)的Bad Request,由于已經(jīng)在第2步被URL Rewrite成合法的形式。因此剩余的處理也就沒(méi)有任何問(wèn)題了。

這些內(nèi)容在一年半前的文章內(nèi)已經(jīng)提過(guò),不過(guò)現(xiàn)在既然有了ASP.NET MVC,則事情又變得更為復(fù)雜。因?yàn)锳SP.NET Routing除了“匹配”URL的功能之外,還擔(dān)負(fù)著“組裝”URL的職責(zé)。因此,讓ASP.NET Routing能夠識(shí)別出Rewrite后的URL不難,但是如何同時(shí)讓它又可以“組裝”出Rewrite前的URL,這就需要一些小技巧了。例如以下的Route配置只能識(shí)別出URL輸入(/products?keywords=xxx)但不能組裝出我們需要的URL(/products/xxx):

routes.MapRoute(      "Product.List",      "products",      new { controller = "Product", action = "List" });

因此,我們必須這么做:

routes.MapRoute(      "Product.List",      "products/{*keywords}",      new { controller = "Product", action = "List", keywords = "" });

請(qǐng)注意我們讓keywords匹配Path后端全部?jī)?nèi)容,而由于我們又提供了keywords的默認(rèn)值,因此即使是“/products”這樣的Path輸入,也能正確匹配到這條Route規(guī)則——只不過(guò)此時(shí)的Route Value中的keywords字段已經(jīng)不是用戶輸入的內(nèi)容了(因?yàn)橛脩糨斎氲?products/xxx,已經(jīng)被重寫(xiě)為/products?keywords=xxx)。換句話說(shuō),如果有如下的Action,那么它的keywords參數(shù)則永遠(yuǎn)是空字符串:

public ActionResult List(string keywords) { ... }幸好,ASP.NET MVC中存在Model Binder機(jī)制,我們可以編寫(xiě)一個(gè)Model Binder來(lái)指定這個(gè)參數(shù)的獲取位置:

public class FromQueryBinder : IModelBinder  {      public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)      {          return controllerContext.HttpContext.Request.QueryString[bindingContext.ModelName];      }  }

再將其運(yùn)用到List的keywords參數(shù)上去:

public ActionResult List(      [ModelBinder(typeof(FromQueryBinder))]string keywords)

由于參數(shù)名是keywords,因此bindingContext.ModelName也是keywords,于是從Query String中便可以取到我們需要的內(nèi)容了。至于在進(jìn)行URL生成的時(shí)候,我們還是可以之間一樣添加一個(gè)keywords字段到Route Value中去,于是在我們先前配置的Route規(guī)則中便會(huì)組裝成合適的Path了(即/products/xxx)。

在這個(gè)例子中,我們讓keywords匹配Path后端全部?jī)?nèi)容,但是如果是Path中間某一段需要有特殊字符怎么辦呢?其實(shí)也一樣,只是在進(jìn)行URL Rewrite的時(shí)候,需要在最終重寫(xiě)的時(shí)候填寫(xiě)一個(gè)“假”的值就可以了,如這樣的Route規(guī)則:

routes.MapRoute(      "Product.List",      "products/{keywords}/page",      new { controller = "Product", action = "List" });

而IIS級(jí)別的URL Rewrite重寫(xiě)的規(guī)則就可以是:

RewriteRule  ^/products/([^/]*)/(.*)     /products/useless-segement/$2?keywords=$1     [I,L,U]這樣,如果用戶輸入/products/xxx/2就會(huì)被重寫(xiě)成/products/useless-token/2?keywords=xxx——事實(shí)上,在***個(gè)示例中我們也可以這么做,只是我“不習(xí)慣”增加一個(gè)偽造的值而已。

以上解決方案可以在IIS 6與IIS 7的Classic Mode中正常使用,只可惜在IIS 7的Intergrated Mode中,可能是由于ASP.NET接管了IIS的部分邏輯,因此會(huì)很早拋出“IIS級(jí)別”,而不是“ASP.NET級(jí)別”的Bad Request異常。如果您遇到了這種方式,就必須通過(guò)以下三個(gè)步驟來(lái)擺脫這個(gè)麻煩的問(wèn)題了:

設(shè)置AllowRestrictedChars:KB820129(讓IIS 7接受特殊字符)

設(shè)置VerificationCompatibility:KB826437中除了“安裝.NET 1.1 SP1”以外的步驟(讓ASP.NET接受特殊字符)

將ASP.NET頁(yè)面的ValidateRequest設(shè)為False

其實(shí)您只要經(jīng)過(guò)了這三步修改,對(duì)于目前這個(gè)案例,即使不用IIS級(jí)別的URL Rewrite應(yīng)該也沒(méi)有問(wèn)題了。

上述就是小編為大家分享的和淺析ASP.NET MVC中關(guān)于URL Rewrite的實(shí)現(xiàn)了,如果剛好有類(lèi)似的疑惑,不妨參照上述分析進(jìn)行理解。如果想知道更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI