Url地址重写
一 什么是url重写
URL 重写是截取传入 Web 请求并自动将请求重定向到其他 URL 的过程。比如浏览器发来请求 hostname/101.aspx ,服务器自动将这个请求中定向为http://hostname/list.aspx ?id=101。 会人为改为 hostname/101.shtml
url重写的优点在于:
l 缩短url,隐藏实际路径提高安全性
l 易于用户记忆和键入。
l 易于被搜索引擎收录
二 实现url重写的基本方法
1. 创建类项目UrlRewriter,项目中增加三个类URLRewriter.Config.cs,URLRewriter.Form.cs,URLRewriter.Module.cs
using System; using System.Configuration; using System.Collections; 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. public class UrlsConfig { public static UrlsSection GetConfig() { return (UrlsSection)System.Configuration.ConfigurationManager.GetSection("CustomConfiguration"); } } public class UrlsSection : ConfigurationSection { [ConfigurationProperty("urls",IsDefaultCollection = false)] public UrlsCollection Urls { get { return (UrlsCollection)this["urls"]; } } } // Define the UrlsCollection that contains UrlsConfigElement elements. public class UrlsCollection : ConfigurationElementCollection { protected override ConfigurationElement CreateNewElement() { return new UrlConfigElement(); } protected override Object GetElementKey(ConfigurationElement element) { return ((UrlConfigElement)element).VirtualUrl; } public UrlConfigElement this[int index] { get { return (UrlConfigElement)BaseGet(index); } } } // Define the UrlConfigElement. public class UrlConfigElement : ConfigurationElement { [ConfigurationProperty("virtualUrl", IsRequired = true)] public string VirtualUrl { get { return (string)this["virtualUrl"]; } set { this["virtualUrl"] = value; } } [ConfigurationProperty("destinationUrl", IsRequired = true)] public string DestinationUrl { get { return (string)this["destinationUrl"]; } set { this["destinationUrl"] = value; } } } } using System; using System.Data; using System.Configuration; using System.Web; using System.Web.Security; using System.Web.UI; using System.Web.UI.WebControls; using System.Web.UI.WebControls.WebParts; using System.Web.UI.HtmlControls; /// <summary> /// FormRewriter 的摘要说明 /// </summary> namespace URLRewriter.Form { public class FormRewriterControlAdapter : System.Web.UI.Adapters.ControlAdapter { public FormRewriterControlAdapter() { } protected override void Render(HtmlTextWriter writer) { base.Render(new RewriteFormHtmlTextWriter(writer)); } } public class RewriteFormHtmlTextWriter : HtmlTextWriter { public RewriteFormHtmlTextWriter(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") { HttpContext context = HttpContext.Current; if (context.Items["ActionAlreadyWritten"] == 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); } } } using System; using System.Web; using System.Text.RegularExpressions; using System.Configuration; using URLRewriter.Config; namespace URLRewriter { public class RewriterModule : IHttpModule { public void Init(HttpApplication app) { // WARNING! This does not work with Windows authentication! // If you are using Windows authentication, change to app.BeginRequest app.AuthorizeRequest += new EventHandler(this.URLRewriter); } protected void URLRewriter(object sender, EventArgs e) { HttpApplication app = (HttpApplication) sender; string requestedPath = app.Request.Path; // get the configuration rules UrlsCollection rules = UrlsConfig.GetConfig().Urls; for (int 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) + "$"; Regex re = new Regex(lookFor, 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; } } } public void Dispose() { } } /// <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 { #region RewriteUrl /// <summary> /// Rewrite's a URL using <b>HttpContext.RewriteUrl()</b>. /// </summary> /// <param name="context">The HttpContext object to rewrite the URL to.</param> /// <param name="sendToUrl">The URL to rewrite to.</param> internal static void RewriteUrl(HttpContext context, string sendToUrl) { string x, y; RewriteUrl(context, sendToUrl, out x, out y); } /// <summary> /// Rewrite's a URL using <b>HttpContext.RewriteUrl()</b>. /// </summary> /// <param name="context">The HttpContext object to rewrite the URL to.</param> /// <param name="sendToUrl">The URL to rewrite to.</param> /// <param name="sendToUrlLessQString">Returns the value of sendToUrl stripped of the querystring.</param> /// <param name="filePath">Returns the physical file path to the requested page.</param> internal static void RewriteUrl(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); } #endregion /// <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) { 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); } } } } }
2.在web.config里设置如下: Code <?xml version="1.0"?> <configuration> <configSections> <section name="CustomConfiguration" type="URLRewriter.Config.UrlsSection, URLRewriter" /> </configSections> <CustomConfiguration> <urls> <add virtualUrl="~/microsoft*.*" destinationUrl="~/default.aspx?id=abc" /> <add virtualUrl="~/microsoft*" destinationUrl="~/default.aspx" /> <add virtualUrl="~/m/i/c/rosoft.aspx" destinationUrl="~/default.aspx" /> <add virtualUrl="~/cc*.*" destinationUrl="~/default2.aspx?id=11" /> </urls> </CustomConfiguration> <system.web> <httpModules> <add type="URLRewriter.RewriterModule, URLRewriter" name="RewriterModule"/> </httpModules> <authentication mode="Forms"/> </system.web> </configuration> 3.处理回发 在重写后的url里如果产生回发,例如有一个按钮,又调用了该被重写的aspx,用户浏览器中将会显示该aspx文件实际的地址,也就是http://hostname/default.aspx?id=11。但从用户的角度考虑,如 果单击按钮时突然看到 URL 更改会使他们感到不安。因此必须解决这个问题。 自己定义一个Actionlessform类,在aspx中不再使用系统提供的form 标记 Code using System; using System.Web.UI; using System.Web.UI.WebControls; using System.ComponentModel; namespace ActionlessForm { /// <summary> /// The Form class extends the HtmlForm HTML control by overriding its RenderAttributes() /// method and NOT emitting an action attribute. /// </summary> public class Form : System.Web.UI.HtmlControls.HtmlForm { /// <summary> /// The RenderAttributes method adds the attributes to the rendered <form> tag. /// We override this method so that the action attribute is not emitted. /// </summary> protected override void RenderAttributes(HtmlTextWriter writer) { // write the form's name writer.WriteAttribute("name", this.Name); base.Attributes.Remove("name"); // write the form's method writer.WriteAttribute("method", this.Method); base.Attributes.Remove("method"); // remove the action attribute base.Attributes.Remove("action"); // finally write all other attributes this.Attributes.Render(writer); if (base.ID != null) writer.WriteAttribute("id", base.ClientID); } } } 创建此类并对其进行编译之后,要在 ASP.NET Web 应用程序中使用它,应首先将其添加到 Web 应用程序的 References 文件夹中。然后,要 使用它来代替 HtmlForm 类,做法是在 ASP.NET 网页的顶部添加以下内容: <%@ Register TagPrefix="af" Namespace="ActionlessForm" Assembly="ActionlessForm" %>
111111