UrlRewrite,Url重写,无扩展名重写
A. 最简单的改写Global.asax:
{
String oldUrl = System.Web.HttpContext.Current.Request.RawUrl;
//其中()最为一个整体,.+任意多个除了()以外的字符,^与字符串开始的地方匹配
//d+任意多个数字,w+任意多个字母或数字或下划线
String pattern = @"^(.+)/test4/(d+).aspx/(w+)";
String replace = @"~/test4.aspx?NID=$1&id=$2&uid=$3";
if(Regex.IsMatch(oldUrl,pattern,RegexOptions.IgnoreCase | RegexOptions.Compiled))
{
String newUrl=Regex.Replace(oldUrl,pattern,replace,RegexOptions.Compiled| RegexOptions.IgnoreCase);
Context.RewritePath(newUrl);
}
}
B.研究Aspx网站的UrlRewrite组件(Net2.0):
namespace UrlRewriter
{
/// <summary>
/// 实现接口IHttpModule
/// </summary>
public class HttpModule:System.Web.IHttpModule
{
#region "IHttpModule成员"
public void Dispose()
{
throw new Exception("The mothod or operation is not implemented.");
}
public void Init(System.Web.HttpApplication context)
{
throw new Exception("The mothod or operation is not implemented.");
}
#endregion
#region IHttpModule 成员
void System.Web.IHttpModule.Dispose()
{
throw new Exception("The method or operation is not implemented.");
}
void System.Web.IHttpModule.Init(System.Web.HttpApplication context)
{
context.BeginRequest += new EventHandler(Module_BeginRequest);
context.EndRequest += new EventHandler(Module_EndRequest);
}
void Module_EndRequest(object sender, EventArgs e)
{
}
void Module_BeginRequest(object sender, EventArgs e)
{
System.Web.HttpContext hc = (sender as System.Web.HttpApplication).Context;
String url = hc.Request.Path.ToLower();
url = RuleParser.Parse(url);
if (!String.IsNullOrEmpty(url))
hc.RewritePath(url);
}
#endregion
}
/// <summary>
/// 规则转换
/// </summary>
public static class RuleParser
{
private static Settings settings = System.Configuration.ConfigurationManager.GetSection("rewriter") as Settings;
private static System.Collections.Specialized.NameValueCollection cache = new System.Collections.Specialized.NameValueCollection(settings.maxcache);
public static String Parse(String url)
{
String k = Utility.Hash.md5(url);
String s = CheckCache(k);
if (!String.IsNullOrEmpty(s))
{
return s;
}
System.Text.RegularExpressions.Match match = null;
System.Text.RegularExpressions.Regex regex = null;
foreach (Rule r in settings.rules)
{
regex = new System.Text.RegularExpressions.Regex(r.urlfor, System.Text.RegularExpressions.RegexOptions.IgnoreCase | System.Text.RegularExpressions.RegexOptions.IgnorePatternWhitespace);
match = regex.Match(url);
if (match.Success)
{
System.Text.RegularExpressions.GroupCollection gc = match.Groups;
String[] ss = new String[gc.Count];
Int32 i = 0;
foreach (System.Text.RegularExpressions.Group g in gc)
{
ss[i++] = g.Value;
}
s = String.Format(r.urlnew,ss);
UpdateCache(k, s);
return s;
}
}
return null;
}
private static String CheckCache(String key)
{
if (cache[key] != null)
return cache[key];
else
return null;
}
private static void UpdateCache(String key, String val)
{
if (cache.Count >= settings.maxcache)
{
cache.Remove(cache.GetKey(0));
}
cache.Add(key, val);
}
}
/// <summary>
/// 读取web.Config中<rewriter>
/// </summary>
public sealed class Configuration : System.Configuration.IConfigurationSectionHandler
{
public Object Create(Object parent, Object input, System.Xml.XmlNode section)
{
Rule r = new Rule();
Settings settings = new Settings();
settings.maxcache = Int32.Parse(section.Attributes["maxcache"].Value);
foreach (System.Xml.XmlNode xn in section.ChildNodes)
{
if (xn.HasChildNodes)
{
//get <for> value
if (xn.FirstChild.HasChildNodes)
r.urlfor = xn.FirstChild.FirstChild.Value;
else
r.urlfor = xn.FirstChild.Value;
//get <new> value
if (xn.LastChild.HasChildNodes)
r.urlnew = xn.LastChild.FirstChild.Value;
else
r.urlnew = xn.LastChild.Value;
}
settings.rules.Add(r);
}
return settings;
}
}
/// <summary>
/// 存放Url,及其转换规则
/// </summary>
public class Settings
{
public Int32 maxcache=1024;
public System.Collections.Generic.List<Rule> rules = new System.Collections.Generic.List<Rule>();
}
/// <summary>
/// 规则
/// </summary>
public struct Rule
{
public String urlfor;
public String urlnew;
}
}
namespace UrlRewriter.Utility
{
/// <summary>
/// 加密
/// </summary>
public static class Hash
{
public static String md5(String s)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(s, "MD5").ToLower();
}
public static String sha1(String s)
{
return System.Web.Security.FormsAuthentication.HashPasswordForStoringInConfigFile(s, "SHA1").ToLower();
}
}
}
<configuration>
<!--添加策略配置节-->
<configSections>
<section name="rewriter" type="UrlRewriter.Configuration,UrlRewriter"/>
</configSections>
</connectionStrings>
<system.web>
<!--添加模块-->
<httpModules>
<add name="UrlRewriter" type="UrlRewriter.HttpModule,UrlRewriter" />
</httpModules>
</system.web>
<!--地址重写策略-->
<rewriter maxcache="2048">
<rule>
<for><![CDATA[/test3/(w)]]></for>
<new><![CDATA[~/test3.aspx?p={1}]]></new>
</rule>
</rewriter>
测试结果:
重写1
前:
http://localhost:3142/WebExample2/test3/a
后:
http://localhost:3142/WebExample2/test3.aspx?p=a
重写2
前:
http://localhost:3142/WebExample2/test3.aspx/a
后:
http://localhost:3142/WebExample2/test3.aspx?p=a
重写3
前:
http://localhost:3142/WebExample2/(\w)
后:
没有转成
C. 研究UrlRewriting.net,只需要添加Intelligencia.UrlRewriter.dll,设置Web.Config即可。
<configSections>
<section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler,Intelligencia.UrlRewriter"/>
</configSections>
<system.web>
<httpModules>
<add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule,Intelligencia.UrlRewriter"/>
</httpModules>
</system.web>
<rewriter>
<rewrite url="~/product/(.+).aspx" to="~/product.aspx?category=$1"/>
</rewriter>
</configuration>
D.UrlReWrite(Url重写或伪静态),发现ActionlessForm.dll没什么用(访微软组件所写):
using System;
namespace UrlRewriter.Config
{
// Define a custom section containing a simple element and a collection of the same element.
// It uses two custom types: UrlsCollection and UrlsConfigElement.
class UrlsConfig
{
public static UrlsSection GetConfig()
{
return (UrlsSection)System.Configuration.ConfigurationManager.GetSection("CustomConfiguration");
}
}
public class UrlsSection:System.Configuration.ConfigurationSection
{
[System.Configuration.ConfigurationProperty("urls",IsDefaultCollection=false)]
public UrlsCollection Urls
{
get
{
return (UrlsCollection)this["urls"];
}
}
}
// Define the UrlsCollection that contains UrlsConfigElement elements.
public class UrlsCollection:System.Configuration.ConfigurationElementCollection
{
protected override System.Configuration.ConfigurationElement CreateNewElement()
{
return new UrlConfigElement();
}
protected override object GetElementKey(System.Configuration.ConfigurationElement element)
{
return ((UrlConfigElement)element).VirtualUrl;
}
public UrlConfigElement this[Int32 index]
{
get
{
return (UrlConfigElement)BaseGet(index);
}
}
}
// Define the UrlConfigElement.
public class UrlConfigElement : System.Configuration.ConfigurationElement
{
[System.Configuration.ConfigurationProperty("virtualUrl",IsRequired=true)]
public String VirtualUrl
{
get
{
return (String)this["virtualUrl"];
}
set
{
this["virtualUrl"]=value;
}
}
[System.Configuration.ConfigurationProperty("destinationUrl",IsRequired=true)]
public String DestinationUrl
{
get
{
return (String)this["destinationUrl"];
}
set
{
this["destinationUrl"] = value;
}
}
}
}
using System;
namespace UrlRewriter
{
public class RewriterModule : System.Web.IHttpModule
{
public void Dispose()
{
}
public void Init(System.Web.HttpApplication context)
{
// WARNING! This does not work with Windows authentication!
// If you are using Windows authentication, change to app.BeginRequest
context.AuthorizeRequest += new EventHandler(URLRewriter);
}
protected void URLRewriter(Object sender, EventArgs e)
{
System.Web.HttpApplication app =(System.Web.HttpApplication)sender;
String requestedPath = app.Request.Path;
// get the configuration rules
UrlRewriter_1.Config.UrlsCollection rules = UrlRewriter.Config.UrlsConfig.GetConfig().Urls;
for (Int32 i = 0; i < rules.Count; i++)
{
// get the pattern to look for, and Resolve the Url (convert ~ into the appropriate directory)
String lookFor = "^" + RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath, rules[i].VirtualUrl) + "$";
System.Text.RegularExpressions.Regex re=new System.Text.RegularExpressions.Regex(lookFor,System.Text.RegularExpressions.RegexOptions.IgnoreCase);
if(re.IsMatch(requestedPath))
{
String sendToUrl=RewriterUtils.ResolveUrl(app.Context.Request.ApplicationPath,re.Replace(requestedPath,rules[i].DestinationUrl));
RewriterUtils.RewriteUrl(app.Context,sendToUrl);
break;
}
}
}
}
/// <summary>
/// Provides utility helper methods for the rewriting HttpModule and HttpHandler.
/// </summary>
/// <remarks>This class is marked as internal, meaning only classes in the same assembly will be able to access its methods.</remarks>
internal class RewriterUtils
{
internal static void RewriteUrl(System.Web.HttpContext context, String sendToUrl)
{
String x, y;
RewriteUrl(context, sendToUrl,out x,out y);
}
internal static void RewriteUrl(System.Web.HttpContext context, String sendToUrl, 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);
// rewrite the path...
context.RewritePath(sendToUrlLessQString, String.Empty, queryString);
}
/// <summary>
/// Converts a URL into one that is usable on the requesting client.
/// </summary>
/// <remarks>Converts ~ to the requesting application path. Mimics the behavior of the
/// <b>Control.ResolveUrl()</b> method, which is often used by control developers.</remarks>
/// <param name="appPath">The application path.</param>
/// <param name="url">The URL, which might contain ~.</param>
/// <returns>A resolved URL. If the input parameter <b>url</b> contains ~, it is replaced with the
/// value of the <b>appPath</b> parameter.</returns>
internal static String ResolveUrl(String appPath, String url)
{
// there is no ~ in the first character position, just return the url
if (url.Length == 0 || url[0] != '~')
return url;
else
{
// there is just the ~ in the URL, return the appPath
if (url.Length == 1)
return appPath;
if (url[1] == '/' || url[1] == '\')
{
// url looks like ~/ or ~
if (appPath.Length > 1)
return appPath + "/" + url.ToString();
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);
}
}
}
}
}
总结:,还有提到很多的无扩展名重写,上面的使用HttpModule实现URL重写, 利用ASP.NET提供的HttpContext.RewritePath方法。这个方法允许开发人员动态地重写收到的URL的处理路径,然后让ASP.NET使用刚重写过后的路径来继续执行请求。
其中的UrlRewriter.Form.cs是采用另外一种方式使用Request.PathInfo 参数而不是查询字符串. 这个技术的很好的地方在于,为部署使用这个方法的ASP.NET应用,不需作任何服务器配置改动。在共享主机的环境里,这个技术也行之有效。
其中:UrlRewriter.Form.cs
namespace UrlRewriter_1.Form
{
public class FormRewriterControlAdapter:System.Web.UI.Adapters.ControlAdapter
{
protected override void Render(System.Web.UI.HtmlTextWriter writer)
{
base.Render(writer);
}
}
public class RewriteFormHtmlTextWriter:System.Web.UI.HtmlTextWriter
{
public RewriteFormHtmlTextWriter(System.Web.UI.HtmlTextWriter writer):base(writer)
{
base.InnerWriter = writer.InnerWriter;
}
public RewriteFormHtmlTextWriter(System.IO.TextWriter writer):base(writer)
{
base.InnerWriter = writer;
}
public override void WriteAttribute(string name, string value, bool fEncode)
{
//If the attribute we are writing is the "action" attribute, and we are not on a sub-control,
//then replace the value to write with the raw URL of the request - which ensures that we'll
//preserve the PathInfo value on postback scenarios
if (name == "action")
{
System.Web.HttpContext Context = System.Web.HttpContext.Current;
if (Context.Items[""] == null)
{
//We will use the Request.RawUrl property within ASP.NET to retrieve the origional
//URL before it was re-written.
value = Context.Request.RawUrl;
//Indicate that we've already rewritten the <form>'s action attribute to prevent
//us from rewriting a sub-control under the <form> control
Context.Items["ActionAlreadyWritten"] = true;
}
}
base.WriteAttribute(name, value, fEncode);
}
}
}
它需要使用还要添加App_Browers
Form.browser
可在 <windir>Microsoft.NETFramework<ver>CONFIGBrowsers 中找到现有的浏览器定义
-->
<browsers>
<browser refID="Default">
<controlAdapters>
<adapter controlType="System.Web.UI.HtmlControls.HtmlForm"
adapterType="FormRewriterControlAdapter" />
</controlAdapters>
</browser>
</browsers>
参考文献:http://blog.joycode.com/scottgu/archive/2007/03/01/94004.aspx