ASP.NET URL雙向改寫的實現
我們在進行Web程式開發時,為了進行搜尋引擎優化(SEO),往往需要對web的訪問地址進行優化,如將http://localhost/Default.aspx?tab=performance修改為http://localhost/Default_performance.aspx,後一個地址能夠更好地被搜尋引擎搜尋到,從而達到了搜尋引擎優化的目的。微軟有一個開源類庫URLRewriter可以非常方便地實現url改寫,通過配置在web.config檔案中的對映表將使用者的請求重定向到具體的頁面中,我在“使用URLRewriter進行URL重寫失效”一文中詳細介紹瞭如何使用這個類庫,該類庫是通過asp.net的httpmodules或httphandles來執行的,但如果網站的宿主伺服器不支援asp.net httpmodules和httphandles,則該功能便失效了,這時我們可以通過global中的application_beginrequest事件來進行url重定向。本文在URLRewriter類庫的基礎上進行了改進,並給出了一個相對完整的解決方案。
我們的改進是建立在URLRewriter的基礎之上的,所以URLRewriter原有的東西只要能用,我們都可以直接拿過來,當然,不好的東西要摒棄!
URLRewriter的對映表是直接寫在web.config檔案中的,要讓web.config能識別對映表,必須在configSections節中新增section,告訴程式如何正確解析web.config中未被識別的內容,如原URLRewriter就需要在web.config中新增。我覺得這個方式並不好,首先你需要單獨去編寫一個類庫來解析xml,並在web.config中進行配置,我們完全可以省去這一步。url的對映表可以單獨寫到一個xml檔案中,當程式執行時將xml載入到應用程式快取中,並設定一個快取檔案依賴項,這樣每當管理員修改完對映表後就可以馬上生效。
另外我希望支援url的雙向改寫,即上面提到的兩個url,當使用者輸入第二個url時程式會將請求傳送到第一個url,但瀏覽器中顯示的url不變;當使用者輸入第一個url時,自動跳轉到第二個url,此時瀏覽器中顯示的是第二個url,但是請求仍然是第一個url。聽起來是不是有點繞啊?沒關係,其實也很簡單,基本的需求就是說客戶原來網站中的很多頁面在訪問時都帶了很多引數,做url改寫時都換成新的url了,這時舊的url仍然可以用,客戶想的就是當輸入原來舊的url時能自動跳轉到新的url。這個就是url的雙向改寫!這兩種方式可以分別通過Context.RewritePath()和Context.Response.Redirect()方法來實現,下面我們來看具體的實現。
首先是對映表的實現。我在URLRewriter原有對映表的基礎上做了一點改動,就是給ReWriterRule新增了一個IsDirect屬性,該屬性可選,預設值為False,當值為真時如果使用者請求的url匹配則會進行跳轉,否則只是進行請求對映。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->xml version="1.0"?>
<ReWriterConfig xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<Rules>
<ReWriterRule>
<LookFor>~/Default_(\w+)\.aspxLookFor>
<SendTo>~/Default.aspx?tab=$1SendTo>
ReWriterRule>
<ReWriterRule IsDirect="true">
<LookFor>~/Default\.aspx\?tab=(\w+)LookFor>
<SendTo>~/Default_$1.aspxSendTo>
ReWriterRule>
Rules>
ReWriterConfig>
該對映表支援正規表示式,下面是對應的實體類,用來進行反序列化。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace URLRewriterTest
{
[Serializable]
public class ReWriterConfig
{
public ReWriterRule[] Rules;
}
[Serializable]
public class ReWriterRule
{
private bool _isRedirect = false;
[System.Xml.Serialization.XmlAttribute("IsDirect")]
public bool IsRedirect
{
get { return _isRedirect; }
set { this._isRedirect = value; }
}
public string LookFor { get; set; }
public string SendTo { get; set; }
}
}
下面這個類用來獲取對映表,當程式第一次執行時會將對映表反序列化的結果放到全域性應用程式快取中。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml.Serialization;
using System.IO;
using System.Web.Caching;
namespace URLRewriterTest
{
public class ReWriterConfiguration
{
public static ReWriterConfig GetConfig(string filename)
{
if (HttpContext.Current.Cache["RewriterConfig"] == null)
{
ReWriterConfig config = null;
// Create an instance of the XmlSerializer specifying type and namespace.
XmlSerializer serializer = new XmlSerializer(typeof(ReWriterConfig));
// A FileStream is needed to read the XML document.
using (Stream reader = new FileStream(filename, FileMode.Open))
{
// Declare an object variable of the type to be deserialized.
config = (ReWriterConfig)serializer.Deserialize(reader);
}
HttpContext.Current.Cache.Insert("RewriterConfig", config, new CacheDependency(filename));
}
return (ReWriterConfig)HttpContext.Current.Cache["RewriterConfig"];
}
}
}
我們仍然需要原URLRewriter類庫中的ReWriterUtils類中的方法,不過對其中RewriteUrl方法進行了一點小的改動,增加了一個isRedirect引數,用來決定是執行Context.RewritePath()方法還是Context.Response.Redirect()方法,下面是原始碼。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace URLRewriterTest
{
public class ReWriterUtils
{
///
/// Rewrite's a URL using HttpContext.RewriteUrl().
///
/// The HttpContext object to rewrite the URL to.
/// Redirect or rewrite path.
/// The URL to rewrite to.
public static void RewriteUrl(HttpContext context, string sendToUrl, bool isRedirect)
{
string x, y;
RewriteUrl(context, sendToUrl, isRedirect, out x, out y);
}
///
/// Rewrite's a URL using HttpContext.RewriteUrl().
///
/// The HttpContext object to rewrite the URL to.
/// The URL to rewrite to.
/// Redirect or rewrite path.
/// Returns the value of sendToUrl stripped of the querystring.
/// Returns the physical file path to the requested page.
public static void RewriteUrl(HttpContext context, string sendToUrl, bool isRedirect, out string sendToUrlLessQString, out string filePath)
{
// see if we need to add any extra querystring information
if (context.Request.QueryString.Count > 0)
{
if (sendToUrl.IndexOf('?') != -1)
sendToUrl += "&" + context.Request.QueryString.ToString();
else
sendToUrl += "?" + context.Request.QueryString.ToString();
}
// first strip the querystring, if any
string queryString = String.Empty;
sendToUrlLessQString = sendToUrl;
if (sendToUrl.IndexOf('?') > 0)
{
sendToUrlLessQString = sendToUrl.Substring(0, sendToUrl.IndexOf('?'));
queryString = sendToUrl.Substring(sendToUrl.IndexOf('?') + 1);
}
// grab the file's physical path
filePath = string.Empty;
filePath = context.Server.MapPath(sendToUrlLessQString);
if (isRedirect)
{
// redirect the path
![](https://i.iter01.com/images/53f84b33c304c962f75dcf603922214f13fd9855d1e2c8fca6ecbe4263db00ee.png)
context.Response.Redirect("~/" + sendToUrlLessQString);
}
else
{
// rewrite the path
![](https://i.iter01.com/images/53f84b33c304c962f75dcf603922214f13fd9855d1e2c8fca6ecbe4263db00ee.png)
context.RewritePath("~/" + sendToUrlLessQString, String.Empty, queryString);
}
// NOTE! The above RewritePath() overload is only supported in the .NET Framework 1.1
// If you are using .NET Framework 1.0, use the below form instead:
// context.RewritePath(sendToUrl);
}
///
/// Converts a URL into one that is usable on the requesting client.
///
///
/// Control.ResolveUrl() method, which is often used by control developers.
/// The application path.
/// The URL, which might contain ~.
///
/// value of the appPath parameter.
public static string ResolveUrl(string appPath, string url)
{
if (url.Length == 0 || url[0] != '~')
return url; // there is no ~ in the first character position, just return the url
else
{
if (url.Length == 1)
return appPath; // there is just the ~ in the URL, return the appPath
if (url[1] == '/' || url[1] == '\\')
{
// url looks like ~/ or ~\
if (appPath.Length > 1)
return appPath + "/" + url.Substring(2);
else
return "/" + url.Substring(2);
}
else
{
// url looks like ~something
if (appPath.Length > 1)
return appPath + "/" + url.Substring(1);
else
return appPath + url.Substring(1);
}
}
}
}
}
最後就是編寫Global中的Application_BeginRequest事件了,在原有URLRewriter的基礎上稍作修改。
Code highlighting produced by Actipro CodeHighlighter (freeware)
http://www.CodeHighlighter.com/
-->protected void Application_BeginRequest(object sender, EventArgs e)
{
string requestedPath = Request.RawUrl.ToString();
// get the configuration rules
string filename = Context.Server.MapPath(".") + "//ReWriterRules.xml";
ReWriterConfig rules = ReWriterConfiguration.GetConfig(filename);
// iterate through each rule
![](https://i.iter01.com/images/53f84b33c304c962f75dcf603922214f13fd9855d1e2c8fca6ecbe4263db00ee.png)
for (int i = 0; i < rules.Rules.Length; i++)
{
// get the pattern to look for, and Resolve the Url (convert ~ into the appropriate directory)
string lookFor = "^" + ReWriterUtils.ResolveUrl(Context.Request.ApplicationPath, rules.Rules[i].LookFor) + "$";
// Create a regex (note that IgnoreCase is set
![](https://i.iter01.com/images/53f84b33c304c962f75dcf603922214f13fd9855d1e2c8fca6ecbe4263db00ee.png)
Regex re = new Regex(lookFor, RegexOptions.IgnoreCase);
// See if a match is found
if (re.IsMatch(requestedPath))
{
// match found - do any replacement needed
string sendToUrl = ReWriterUtils.ResolveUrl(Context.Request.ApplicationPath, re.Replace(requestedPath, rules.Rules[i].SendTo));
// Rewrite or redirect the URL
ReWriterUtils.RewriteUrl(Context, sendToUrl, rules.Rules[i].IsRedirect);
break; // exit the for loop
}
}
}
好了,大功告成!使用上面的對映表,當你輸入http://localhost/Default_performance.aspx時訪問正常,事實上Default_後面可以新增任何字元,這些字元都將作為Default.aspx頁面tab引數的值。同時,當你輸入http://localhost/Default.aspx?tab=performance時頁面會自動跳轉到前面一個url,tab引數的值將被作為url的一部分。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/12639172/viewspace-617171/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 【ASP.NET Core】URL重寫ASP.NET
- Nginx實現URL重寫Nginx
- 雙向繫結的極簡實現
- Vue雙向繫結實現Vue
- 實現雙向連結串列
- PHP實現url重寫和.htaccessPHP
- 雙向連結串列的功能實現(初版
- 梳理vue雙向繫結的實現原理Vue
- vue實現prop雙向繫結Vue
- Go實現雙向連結串列Go
- java實現雙向連結串列Java
- js 實現vue的雙向資料繫結JSVue
- vue資料雙向繫結的實現原理Vue
- 雙向資料繫結實現原理
- NodeJS Https HSM雙向認證實現NodeJSHTTP
- 簡要實現vue雙向繫結Vue
- angular雙向繫結簡單實現Angular
- javascript實現雙向資料繫結JavaScript
- 基於vue實現的雙向資料繫結Vue
- Vue 中實現雙向繫結的 4 種方法Vue
- 資料結構(雙向連結串列的實現)資料結構
- JavaScript實現簡單的雙向資料繫結JavaScript
- 剖析Vue原理&實現雙向繫結MVVMVueMVVM
- 簡單實現一個雙向繫結
- WPF之AvalonEdit實現MVVM雙向繫結MVVM
- Vue雙向繫結原理,教你一步一步實現雙向繫結Vue
- 通過原生js實現資料的雙向繫結JS
- Vue父子元件雙向繫結傳值的實現方法Vue元件
- redis 雙寫實現策略 && hash取模Redis
- 5分鐘教你實現Vue雙向繫結Vue
- mvvm-simple雙向繫結簡單實現MVVM
- Vue雙向繫結的實現原理系列(一):Object.definepropertyVueObject
- 手動實現vue元件間的雙向資料繫結Vue元件
- MVVM雙向繫結機制的原理和程式碼實現MVVM
- 寫一個簡單的Linkedlist,實現增刪改查
- 在winform中如何實現雙向資料繫結?ORM
- 資料結構-雙向連結串列(Python實現)資料結構Python
- 請使用 js 實現一個雙向連結串列JS
- URL重寫(rewrite)的具體實現與異常問題解決