最新文章專題視頻專題問答1問答10問答100問答1000問答2000關(guān)鍵字專題1關(guān)鍵字專題50關(guān)鍵字專題500關(guān)鍵字專題1500TAG最新視頻文章視頻文章20視頻文章30視頻文章40視頻文章50視頻文章60 視頻文章70視頻文章80視頻文章90視頻文章100視頻文章120視頻文章140 視頻2關(guān)鍵字專題關(guān)鍵字專題tag2tag3文章專題文章專題2文章索引1文章索引2文章索引3文章索引4文章索引5123456789101112131415文章專題3
當前位置: 首頁 - 科技 - 知識百科 - 正文

一個完整的ASP.NET 2.0 URL重寫方案[翻譯]

來源:懂視網(wǎng) 責(zé)編:小采 時間:2020-11-27 22:43:49
文檔

一個完整的ASP.NET 2.0 URL重寫方案[翻譯]

一個完整的ASP.NET 2.0 URL重寫方案[翻譯]:這篇文章描述了一個完整的 ASP.NET 2.0 URL 重寫方案。這個方案使用正則表達式來定義重寫規(guī)則并解決通過虛擬 URLs 訪問頁面產(chǎn)生回發(fā)事件的一些可能的困難。 為什么要重寫 URL 將 URL 重寫方法應(yīng)用到你的 ASP.Net 應(yīng)用程序的兩個主要原因是:可用性和可維
推薦度:
導(dǎo)讀一個完整的ASP.NET 2.0 URL重寫方案[翻譯]:這篇文章描述了一個完整的 ASP.NET 2.0 URL 重寫方案。這個方案使用正則表達式來定義重寫規(guī)則并解決通過虛擬 URLs 訪問頁面產(chǎn)生回發(fā)事件的一些可能的困難。 為什么要重寫 URL 將 URL 重寫方法應(yīng)用到你的 ASP.Net 應(yīng)用程序的兩個主要原因是:可用性和可維

這篇文章描述了一個完整的 ASP.NET 2.0 URL 重寫方案。這個方案使用正則表達式來定義重寫規(guī)則并解決通過虛擬 URLs 訪問頁面產(chǎn)生回發(fā)事件的一些可能的困難。

為什么要重寫 URL ?

將 URL 重寫方法應(yīng)用到你的 ASP.Net 應(yīng)用程序的兩個主要原因是:可用性和可維護性。

可用性

誰都知道,相對于難于辨認的帶參數(shù)的長的查詢路徑,用戶更喜歡一些短的、簡潔的 URL。任何時候,一個容易記住和敲入的路徑比添加到收藏夾更有用。其次,當一個瀏覽器的收藏夾不可用時,記住的地址總比在搜索引擎中輸入關(guān)鍵字進行搜索,然后再查找要強的多。比較下面的兩個地址:

 

(1)

http://www.somebloghost.com/Blogs/Posts.aspx?Year=2006&Month=12&Day=10

(2)

http://www. somebloghost.com/Blogs/2006/12/10/

 

第一個 URL 包含了查詢字符串;第二個URL包含的信息可以讓用戶清楚的看到他看的東西,它還可以使用戶更容易的修改地址欄的內(nèi)容,如:http://www.somehost.com/Blogs/2006/12/.

可維護性

在很多WEB應(yīng)用程序中,開發(fā)人員經(jīng)常會將頁面從一個目錄移到另一個目錄,讓我們假設(shè)一開始有兩個可用頁面: http://www.somebloghost.com/Info/Copyright.aspx 和 http://www.somebloghost.com/Support/Contacts.aspx,但是后來開發(fā)者將 Copyright.aspx 和 Contacts.aspx 移到了 Help 目錄,用戶收藏起來地址就需要重新定位。這個問題雖然可以簡單的用 Response.Redirect(new location) 來解決,但是如果有成百上千的頁面呢?應(yīng)用程序中就會包含大量的無效鏈接。

使用 URL 重寫,允許用戶只需修改配置文件,這種方法可以讓開發(fā)者將web應(yīng)用程序邏輯結(jié)構(gòu)與物理結(jié)構(gòu)獨立開來。

ASP.NET 2.0 中的原有的URL 映射

ASP.NET 2.0 為 web 應(yīng)用程序提供了一個開箱即用的映射靜態(tài) URL 的解決方案。這個方案不用編寫代碼就可以在 web.config 中將舊的 URLs 映射到新的地址。 要使用 URL 映射,只需在 web.config 文件的 system.web 節(jié)中創(chuàng)建一個新的 urlMappings 節(jié) ,并添加要映射的地址 (“ ~/ ”指向應(yīng)用程序的根目錄):

<urlMappings enabled="true">

   <add url="~/Info/Copyright.aspx" mappedUrl="~/Help/Copyright.aspx" />

   <add url="~/Support/Contacts.aspx" mappedUrl="~/Help/Contacts.aspx" />

</urlMappings>

這樣,如果用戶輸入 http://www.somebloghost.com/Support/Contacts.aspx, 它將看到 http://www.somebloghost.com/Help/Contacts.aspx , 而他并不知道那個頁已經(jīng)移除。

這個方案對于只有兩個頁面被移到其它位置的情況是足夠的。但它對有一打的需要重定位的頁或者需要創(chuàng)建一個整潔的URL來說,它是不合適的。另一個使用Asp.Net 的原有的URL映射技術(shù)的不太好的地方是:如果 Contacts.aspx 頁包含的元素在回發(fā)到服務(wù)器時(這是非??赡艿?, 用戶將會驚奇的發(fā)現(xiàn)地址 http://www.somebloghost.com/Support/Contacts.aspx 卻變成了 http://www.somebloghost.com/Help/Contacts.aspx

  這是因為ASP.NET 引擎用頁面的實際地址修改了表單formaction 屬性 ,所以表單就變成了下面的樣子:

<form name="formTest" method="post"
action="http://www.simple-talk.com/Help/Contacts.aspx" id="formTest">

</form>

這樣看來,URL 映射在ASP.NET 2.0 中幾乎是無用的。我們應(yīng)當能夠使用一個映射規(guī)則來指定一系列相似的 URL。最好的解決方案就是使用正則表達式 ( Wikipedia 上可以查看概覽,and 在 .NET 下的實現(xiàn)可以查看 MSDN), 但由于 ASP.NET 2.0 映射不支持正則表達式,所以我們需要開發(fā)一個內(nèi)建到 URL 映射的不同的方案- URL 重寫模塊。 最好的方法就是創(chuàng)建一個可重用的、簡單的配置模塊來實現(xiàn),顯然我們應(yīng)創(chuàng)建一個 HTTP 模塊 (關(guān)于 HTTP 模塊的詳細信息請查看 MSDN 雜志) 并在獨立的程序集中實現(xiàn)。要使這個程序集簡單易用,我們應(yīng)實現(xiàn)這個重寫引擎的可配置性,即能夠在 web.config 中指定規(guī)則。

 

 

在開發(fā)過程中,我們應(yīng)能使這個重寫模塊打開或關(guān)閉 (比如你有一個較難捕獲的bug,而它可能是由不正確的重寫模塊引起的)這樣在 web.config 中對重寫模塊的配置節(jié)進行打開或關(guān)閉就成為一個選擇。這樣,在 web.config 中,一個配置節(jié)的示例如下:

<rewriteModule>

  <rewriteOn>true</rewriteOn>

  <rewriteRules>

      <rule source="(\d+)/(\d+)/(\d+)/"
         destination="Posts.aspx?Year=$1&Month=$2&Day=$3"/>

      <rule source="(.*)/Default.aspx"
         destination="Default.aspx?Folder=$1"/>

  </rewriteRules>

</rewriteModule>

這樣,所有像: http://localhost/Web/2006/12/10/ 這樣的請示,將會在內(nèi)部將會用帶參數(shù)的請求重定向到 Posts.aspx 。

請注意: web.config 是一個結(jié)構(gòu)良好的 XML 文件, 它禁止在屬性值中使用 & 符號,所以在例子中,應(yīng)當使用 & 代替。

要在配置文件中使用這個重寫模塊,還需要注冊節(jié)和指定處理模塊,像下面這樣增加一個configSections配置節(jié):

 <configSections>

    <sectionGroup name="modulesSection">

      <section name="rewriteModule" type="RewriteModule.
RewriteModuleSectionHandler, RewriteModule"/>

    </sectionGroup>

  </configSections>

這樣你就可以在 configSections 節(jié)的后面這樣使用了:

<modulesSection>

    <rewriteModule>

      <rewriteOn>true</rewriteOn>

      <rewriteRules>

              <rule source="(\d+)/(\d+)/(\d+)/" destination="Post.aspx?Year=$1&Month=$2&Day=$3"/>

              <rule source="(.*)/Default.aspx" destination="Default.aspx?Folder=$1"/>

      </rewriteRules>

    </rewriteModule>

  </modulesSection>

另一個我們在開發(fā)重寫模塊過程中要做的就是還需要允許在虛擬路徑中傳遞參數(shù),象這樣: http://www.somebloghost.com/2006/12/10/?Sort=Desc&SortBy=Date 。所以我們還需要有一個檢測通過虛擬 URL 傳遞參數(shù)的解決方案

 

 

接下來讓我們來創(chuàng)建類庫。首先,我們要引用 System.Web 程序集,這樣我們可以實現(xiàn)一些基于 web 特殊功能。如果要使我們的模塊能夠訪問 web.config,還需要引用 System.Configuration 程序集。

 

處理配置節(jié)

要能處理 web.config 中的配置,我們必需創(chuàng)建一個實現(xiàn)了 IConfigurationSectionHandler 接口的類 (詳情查看 MSDN )。如下:

using System;

using System.Collections.Generic;

using System.Text;

using System.Configuration;

using System.Web;

using System.Xml;

 

 

namespace RewriteModule

{

    public class RewriteModuleSectionHandler : IConfigurationSectionHandler

    {

 

        private XmlNode _XmlSection;

        private string _RewriteBase;

        private bool _RewriteOn;

 

        public XmlNode XmlSection

        {

            get { return _XmlSection; }

        }

 

        public string RewriteBase

        {

            get { return _RewriteBase; }

        }

 

        public bool RewriteOn

        {

            get { return _RewriteOn; }

        }

        public object Create(object parent,
                            object configContext,
                            System.Xml.XmlNode section)

        {

            // set base path for rewriting module to

            // application root

            _RewriteBase = HttpContext.Current.Request.ApplicationPath + "/";

 

            // process configuration section

            // from web.config

            try

            {

                _XmlSection = section;

                _RewriteOn = Convert.ToBoolean(
                            section.SelectSingleNode("rewriteOn").InnerText);

            }

            catch (Exception ex)

            {

                throw (new Exception("Error while processing RewriteModule
configuration section.", ex));

            }

            return this;

        }

    }

}

RewriteModuleSectionHandler 類將在 web.config 中的 XmlNode 通過調(diào)用 Create 方法初始化。XmlNode 類的 SelectSingleNode 方法被用來返回模塊的配置值。

使用重寫的 URL 的參數(shù)

在處理象 http://www. somebloghost.com/Blogs/gaidar/?Sort=Asc (這是一個帶參數(shù)的虛擬 URL ) 虛擬的 URLS 時,能夠清楚的辨別通過虛擬路徑傳遞的參數(shù)是非常重要的,如下:

<rule source="(.*)/Default.aspx" destination="Default.aspx?Folder=$1"/>,

你可能使用這樣的 URL:

http://www. somebloghost.com/gaidar/?Folder=Blogs

它的效果和下面的相似:

http://www. somebloghost.com/Blogs/gaidar/

要處理這個問題,我們需要對'虛擬路徑參數(shù)' 進行包裝。這可以是通過一個靜態(tài)的方法去訪問當前的參數(shù)集:

using System;

using System.Collections.Generic;

using System.Text;

using System.Collections.Specialized;

using System.Web;

 

namespace RewriteModule

{

 

    public class RewriteContext

    {

        // returns actual RewriteContext instance for

        // current request

        public static RewriteContext Current

        {

            get

            {

                // Look for RewriteContext instance in

                // current HttpContext. If there is no RewriteContextInfo

                // item then this means that rewrite module is turned off

                if(HttpContext.Current.Items.Contains("RewriteContextInfo"))

                    return (RewriteContext)
HttpContext.Current.Items["RewriteContextInfo"];

                else

                    return new RewriteContext();

            }

        }

 

        public RewriteContext()

        {

            _Params = new NameValueCollection();

            _InitialUrl = String.Empty;

        }

 

        public RewriteContext(NameValueCollection param, string url)

        {

            _InitialUrl = url;

            _Params = new NameValueCollection(param);

           

        }

 

        private NameValueCollection _Params;

 

        public NameValueCollection Params

        {

            get { return _Params; }

            set { _Params = value; }

        }

 

        private string _InitialUrl;

 

        public string InitialUrl

        {

            get { return _InitialUrl; }

            set { _InitialUrl = value; }

        }

    }

}

可以看到,這樣就可以通過RewriteContext.Current 集合來訪問 “虛擬路徑參數(shù)”了,所有的參數(shù)都被指定成了虛擬路徑或頁面,而不是像查詢字符串那樣了。

重寫 URL

接下來,讓我們嘗試重寫。首先,我們要讀取配置文件中的重寫規(guī)則。其次,我們要檢查那些在 URL 中與規(guī)則不符的部分,如果有,進行重寫并以適當?shù)捻搱?zhí)行。

創(chuàng)建一個 HttpModule:

class RewriteModule : IHttpModule
{

public void Dispose() { }
public void Init(HttpApplication context)

{}

}

當我們添加 RewriteModule_BeginRequest 方法以處理不符合規(guī)則的 URL時,我們要檢查給定的 URL 是否包含參數(shù),然后調(diào)用 HttpContext.Current.RewritePath 來進行控制并給出合適的 ASP.NET 頁。

using System;

using System.Collections.Generic;

using System.Text;

using System.Web;

using System.Configuration;

using System.Xml;

using System.Text.RegularExpressions;

using System.Web.UI;

using System.IO;

using System.Collections.Specialized;

 

namespace RewriteModule

{

    class RewriteModule : IHttpModule

    {

 

        public void Dispose() { }

 

        public void Init(HttpApplication context)

        {

            // it is necessary to

            context.BeginRequest += new EventHandler(
                 RewriteModule_BeginRequest);

        }

 

        void RewriteModule_BeginRequest(object sender, EventArgs e)

        {

 

            RewriteModuleSectionHandler cfg =
(RewriteModuleSectionHandler)
ConfigurationManager.GetSection
("modulesSection/rewriteModule");

 

            // module is turned off in web.config

            if (!cfg.RewriteOn) return;

 

            string path = HttpContext.Current.Request.Path;

 

            // there us nothing to process

            if (path.Length == 0) return;

 

            // load rewriting rules from web.config

            // and loop through rules collection until first match

            XmlNode rules = cfg.XmlSection.SelectSingleNode("rewriteRules");

            foreach (XmlNode xml in rules.SelectNodes("rule"))

            {

                try

                {

                    Regex re = new Regex(
                     cfg.RewriteBase + xml.Attributes["source"].InnerText,
                     RegexOptions.IgnoreCase);

                    Match match = re.Match(path);

                    if (match.Success)

                    {

                        path = re.Replace(
                             path,
                             xml.Attributes["destination"].InnerText);

                        if (path.Length != 0)

                        {

                            // check for QueryString parameters

                       if(HttpContext.Current.Request.QueryString.Count != 0)

                       {

                       // if there are Query String papameters

                       // then append them to current path

                       string sign = (path.IndexOf('?') == -1) ? "?" : "&";

                       path = path + sign +
                          HttpContext.Current.Request.QueryString.ToString();

                       }

                       // new path to rewrite to

                       string rew = cfg.RewriteBase + path;

                       // save original path to HttpContext for further use

                       HttpContext.Current.Items.Add(

                         "OriginalUrl",

                         HttpContext.Current.Request.RawUrl);

                       // rewrite

                       HttpContext.Current.RewritePath(rew);

                       }

                       return;

                    }

                }

                catch (Exception ex)

                {

                    throw (new Exception("Incorrect rule.", ex));

                }

            }

            return;

        }

 

    }

}

 

這個方法必須注冊:

public void Init(HttpApplication context)

{

 context.BeginRequest += new EventHandler(RewriteModule_BeginRequest);

}

但這些僅僅完成了一半,因為重寫模塊還要處理表單的回發(fā)和虛擬路徑參數(shù)集合,而這段代碼中你會發(fā)現(xiàn)并沒處理這些。讓我們先把虛擬路徑參數(shù)放到一邊,先來正確地處理最主要的回發(fā)。

如果我們運行上面的代碼,并通過查看 ASP.NET 的 HTML 源代碼 的 action 會發(fā)現(xiàn),它竟然包含了一個 ASP.NET 的實際路徑頁。例如,我們使用頁 ~/Posts.aspx 來處理像 http://www. somebloghost.com/Blogs/2006/12/10/Default.aspx 的請求, 發(fā)現(xiàn) action="/Posts.aspx"。這意味著用戶并沒有使用虛擬路徑進行回發(fā),而是使用了實際的 http://www. somebloghost.com/Blog.aspx. 這個并不是我們需要的。所以,需要加一段代碼來處理這些不希望的結(jié)果。

首先,我們要在 HttpModule 注冊和實現(xiàn)一個另外的方法:

        public void Init(HttpApplication context)

        {

            // it is necessary to

            context.BeginRequest += new EventHandler(
                 RewriteModule_BeginRequest);

            context.PreRequestHandlerExecute += new EventHandler(
                 RewriteModule_PreRequestHandlerExecute);

        }

 

      void RewriteModule_PreRequestHandlerExecute(object sender, EventArgs e)

        {

            HttpApplication app = (HttpApplication)sender;

            if ((app.Context.CurrentHandler is Page) &&
                 app.Context.CurrentHandler != null)

            {

                Page pg = (Page)app.Context.CurrentHandler;

                pg.PreInit += new EventHandler(Page_PreInit);

            }

        }

這個方法檢查用戶是否請求了一個正常的 ASP.NET 頁,然后為該頁的 PreInit 事件增加處理過程。這兒 RewriteContext 將處理實際參數(shù),然后二次重寫URL。二次重寫是必需的,以使 ASP.NET 能夠在它的表單的action屬性中使用一個虛擬路徑。

void Page_PreInit(object sender, EventArgs e)

        {

            // restore internal path to original

            // this is required to handle postbacks

            if (HttpContext.Current.Items.Contains("OriginalUrl"))

            {

              string path = (string)HttpContext.Current.Items["OriginalUrl"];

 

              // save query string parameters to context

              RewriteContext con = new RewriteContext(
                HttpContext.Current.Request.QueryString, path);

 

              HttpContext.Current.Items["RewriteContextInfo"] =  con;

 

              if (path.IndexOf("?") == -1)

                  path += "?";

              HttpContext.Current.RewritePath(path);

            }

        }

最后,我們來看一下在我們的重寫模塊程序集中的三個類:

 

在 web.config 中注冊重寫模塊

要使用重寫模塊,需要在配置文件中的 httpModules 節(jié)注冊重寫模塊,如下:

<httpModules>

<add name="RewriteModule" type="RewriteModule.RewriteModule, RewriteModule"/>

</httpModules>

使用重寫模塊

在使用重寫模塊時,需要注意:

  • 在 web.config 中來使用一些特殊字符是不可能的,因為它是一個結(jié)構(gòu)良好的 XML 文件,因此,你只能用 HTML 編碼的字符代替,如:使用 & 代替 &。
  • 要在你的 ASPX 中使用相對路徑,需要在HTML標簽調(diào)用 ResolveUrl 方法,如: <img src="<%=ResolveUrl("~/Images/Test.jpg")%>" />。
  • Bear in mind the greediness of regular expressions and put rewriting rules to web.config in order of their greediness, for instance:
  • <rule source="Directory/(.*)/(.*)/(.*)/(.*).aspx"
    destination="Directory/Item.aspx?
    Source=$1&Year=$2&ValidTill=$3&Sales=$4"/>
    <rule source="Directory/(.*)/(.*)/(.*).aspx"
    destination="Directory/Items.aspx?
    Source=$1&Year=$2&ValidTill=$3"/>
    <rule source="Directory/(.*)/(.*).aspx"
    destination="Directory/SourceYear.aspx?
    Source=$1&Year=$2&"/>
    <rule source="Directory/(.*).aspx"
    destination="Directory/Source.aspx?Source=$1"/>
  • 如果你要在頁面中使用 RewriteModule 而不使用 .aspx,就必須在 IIS 中進行配置以使用期望的擴展映射到請求頁,如下節(jié)所述:
  • IIS 配置: 使用帶擴展的重寫模塊代替 .aspx

    要使用帶擴展的重寫模塊代替 .aspx (如 .html or .xml), 必須配置 IIS ,以使這些擴展映射到 ASP.NET 引擎 (ASP.NET ISAPI 擴展)。要進行這些設(shè)置,需要以管理員身份登錄。

    打開 IIS 管理控制臺,并選擇你要配置的站點的虛擬路徑:

    Windows XP (IIS 5)
    Virtual Directory "RW"                                

     

    Windows 2003 Server (IIS 6)
    Default Web Site

    然后在虛擬路徑標簽上點擊 Configuration… 按鈕  (或如果要使用整個站點都做映射就選擇主目錄標簽)。

    Windows XP (IIS 5)                     

    Windows 2003 Server (IIS 6)

    接下來,點擊添加按鈕,并輸入一個擴展,你還需要指定一個 ASP.NET ISAPI 擴展,注意去掉選項的對勾以檢查文件是否存在。

    如果你要把所有的擴展都映射到 ASP.NET,對Windows XP上的 IIS 5 來說只需要設(shè)置 .* 到 ASP.NET ISAPI ,但對 IIS 6 就不一樣了,點擊“添加”然后指定 ASP.NET ISAPI 擴展。

    總結(jié)

    現(xiàn)在,我們已經(jīng)創(chuàng)建了一個簡單的但非常強大的 ASP.NET 重寫模塊,它支持可基于正則表達式的 URLs 和頁面回發(fā),這個解決方案是容易實現(xiàn)的,并且提供給用戶的例子也是可用的,它可以用簡短的、整潔的URL來替代查詢字符串參數(shù)。  要使用這個模塊,只需簡單在你的應(yīng)用程序中對 RewriteModule 進行引用,然后在 web.config 文件中添加幾行代碼以使你不想顯示的 URL 通過正則表達式代替。這個重寫模塊是很容易部署的,因為只需要在web.config中修改任何“虛擬”的URL即可,如果你需要進行測試,還可以對重寫模塊進行關(guān)閉。

    要想對重寫模塊有一個深入的了解,你可以查看本文提供的原代碼。我相信你會發(fā)現(xiàn)這是一個比ASP.NET提供的原始映射更好的體驗。

    聲明:本網(wǎng)頁內(nèi)容旨在傳播知識,若有侵權(quán)等問題請及時與本網(wǎng)聯(lián)系,我們將在第一時間刪除處理。TEL:177 7030 7066 E-MAIL:11247931@qq.com

    文檔

    一個完整的ASP.NET 2.0 URL重寫方案[翻譯]

    一個完整的ASP.NET 2.0 URL重寫方案[翻譯]:這篇文章描述了一個完整的 ASP.NET 2.0 URL 重寫方案。這個方案使用正則表達式來定義重寫規(guī)則并解決通過虛擬 URLs 訪問頁面產(chǎn)生回發(fā)事件的一些可能的困難。 為什么要重寫 URL 將 URL 重寫方法應(yīng)用到你的 ASP.Net 應(yīng)用程序的兩個主要原因是:可用性和可維
    推薦度:
    標簽: 翻譯 2.0 ur
    • 熱門焦點

    最新推薦

    猜你喜歡

    熱門推薦

    專題
    Top