在这里与大家分享一下URL的重写来实现二级域名的访问,这个方法也是在参与项目中学习到。平自己的理解来给大家分享,若有不对还请指出。
大家也知道Asp.Net的生命周期,当客户端请求时,经过IIS解析再到.NET Framework获得请求。在framework中就要进行一系列的处理,然后再返回给IIS最后在到客户端。我暂时知道两种处理URL重写。一种是在Global.asax里来实现,在web.config配置一下就可以实现了;另一种就是接下要写的。
我大概讲下实现思路:
写一个基类继(BaseModelRewriter.cs)承接口(IHttpModule),并且在这个基类写一个abstract RewriterURL();在写一个子类(ModeRewriter.cs)继承基类,并实现oerride Rewriter()接下来我们要重写这个方法;
要写一个方法我们就要做好一些准备,创建一个可序列化的类(ReWriterRule.cs)并以[Serializable()]标记还继承了类(CollectionBase),再写一个类(RewriterConfiguration.cs)主要是定义在Web.config文件中重写配置文件的结构; 再创建一个类(RewriterConfigSerializerSectionHandler.cs)来反序列化标记在Web.config为实例的,它继承接口(IConfigurationSectionHandler);在创建一个类(RewriterFactoryHandler.cs)并继承接口(IHttpHandlerFactory)提供了一个HttpHandler执行重定向。
最后我们还要配置一个web.config就可以实现功能了。还有IIS还要做下泛域名解析。如:xxx.like.com 做配置一下*.like.com;
实现代码如下:
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace ElToolsTest.URLWriter { /// <summary> /// 抽象类 模块重写基类。这类是抽象的,因此必须从。 /// </summary> public abstract class BaseModelRewriter : IHttpModule { /// <summary> /// 实现接口 /// </summary> public virtual void Dispose() { } /// <summary> /// 实现接口 /// </summary> /// <param name="context">一个参考的HttpApplication对象处理这个请求</param> public virtual void Init(HttpApplication context) { //这并不与Windows身份验证的工作! //如果您使用的是Windows身份验证,改变app.beginrequest context.AuthorizeRequest += new EventHandler(this.BaseModelRewriter_AuthoriaeRequest); } /// <summary> /// 当模块的authorizerequest事件触发。 /// </summary> /// <param name="sender">该事件处理程序调用的<看到CREF =“改写”/>方法,通过在和HttpApplication通过通过发送者参数以上结果由</param> /// <param name="e"></param> protected virtual void BaseModelRewriter_AuthoriaeRequest(object sender, EventArgs e) { HttpApplication app = (HttpApplication)sender; Rewriter(app.Request.Url.AbsoluteUri,app); } /// <summary> /// 该重写必须重写的方法。它是在重写传入的逻辑 /// URL 进行 /// <param name="requestedPath">所请求的rawurl。(包括完整的路径和查询字符串。)</param> /// <param name="app">HttpApplication 实例 </param> /// </summary> protected abstract void Rewriter(string requestedPath,HttpApplication app); } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Text.RegularExpressions; namespace ElToolsTest.URLWriter { /// <summary> /// 提供了一个重写Web应用。 /// </summary> public class ModeRewriter : BaseModelRewriter { /// <summary> /// 这种方法是模块BeginRequest事件中调用。 /// </summary> /// <param name="requestedPath">被请求的rawurl(包括路径和查询字符串)</param> /// <param name="app">HttpApplication实例。</param> protected override void Rewriter(string requestedPath, HttpApplication app) { //将本地域名替换成服务域名来匹配 if (requestedPath.IndexOf("localhost") > 0 || requestedPath.IndexOf("192.168.0.3") > 0) { requestedPath = requestedPath.Replace("http://" + app.Request.ServerVariables["HTTP_HOST"], "www.like.com");//把主机名替换为www.baidu.com } else { requestedPath = requestedPath.Replace("http://" + app.Request.ServerVariables["HTTP_HOST"] + app.Request.ApplicationPath, "http://www.like.com"); } //将html,xml以外的所有请求,直接返回,不去匹配 string ftypeRule = @"^*\.(js|jpg|gif|png|css|swf|ico)$"; Regex reFile = new Regex(ftypeRule, RegexOptions.IgnoreCase); if (reFile.IsMatch(requestedPath.ToLower())) { return; } //日志信息跟踪对象 app.Context.Trace.Write("ModuleRewriter", "Entering ModuleRewriter"); //获取配置规则 RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules; for (int i = 0; i < rules.Count; i++) { string LookFor = "^" + rules[i].LookFor + "$"; //正则表达式 Regex res = new Regex(LookFor, RegexOptions.IgnoreCase); if (res.IsMatch(requestedPath)) { //找到的匹配-做任何需要更换 string senderToUrl = RewriterUtils.RewriterUrl(app.Context.Request.ApplicationPath, res.Replace(requestedPath, rules[i].SenderTo)); //日志信息跟踪对象 app.Context.Trace.Write("ModuleRewriter", "Rewriting URL to " + senderToUrl); RewriterUtils.RewriterUrl(app.Context, senderToUrl); break; } } //日志信息跟踪对象 app.Context.Trace.Write("ModuleRewriter", "Exiting ModuleRewriter"); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace ElToolsTest.URLWriter { /// <summary> /// 代表一个重写规则。一个重写规则是由一个模式搜索和替换字符串利用模式(配)。 /// </summary> [Serializable()] public class ReWriterRule { /// <summary> /// 获得或者设置模式寻找 /// </summary> public string LookFor { get; set; } /// <summary> /// 替换字符 /// </summary> public string SenderTo { get; set; } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Collections; namespace ElToolsTest.URLWriter { /// <summary> /// 在Web.config文件的一组rewriterrules的rewriterrulecollection模型。 /// 该rewriterrulecollection表示XML: /// <RewriterRule> /// <LookFor><i>pattern to search for</i></LookFor> /// <SendTo><i>string to redirect to</i></LookFor> /// <RewriterRule> /// <RewriterRule> /// <LookFor><i>pattern to search for</i></LookFor> /// <SendTo><i>string to redirect to</i></LookFor> /// <RewriterRule> /// ... /// <RewriterRule> /// <LookFor><i>pattern to search for</i></LookFor> /// <SendTo><i>string to redirect to</i></LookFor> /// <RewriterRule> /// </summary> [Serializable()]//标记可能序列化类 public class RewriterRuleCollection : CollectionBase { //增加了一个新的rewriterrule到集合。 public virtual void Add(ReWriterRule r) { this.InnerList.Add(r); } //获取或设置在一个指定的序号索引一个rewriterrule public ReWriterRule this[int index] { get { return (ReWriterRule) this.InnerList[index]; } set { this.InnerList[index] = value; } } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Configuration; using System.Xml.Serialization; using System.Xml.XPath; using System.Xml; namespace ElToolsTest.URLWriter { /// <summary> /// 反序列化标记在Web.config为实例的<看到CREF =“rewriterconfiguration”/>类。 /// </summary> public class RewriterConfigSerializerSectionHandler : IConfigurationSectionHandler { /// <summary> /// 创建一个实例 /// </summary> /// <param name="parent"></param> /// <param name="configContext"></param> /// <param name="section"></param> /// <returns></returns> public virtual object Create(object parent, object configContext, System.Xml.XmlNode section) { //创建一个基于rewriterconfiguration型XmlSerializer实例。 XmlSerializer ser = new XmlSerializer(typeof(RewriterConfiguration)); //返回反序列化的对象从web.config XML return ser.Deserialize(new XmlNodeReader(section)); } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.UI; using System.Text.RegularExpressions; namespace ElToolsTest.URLWriter { /// <summary> /// 提供了一个HttpHandler执行重定向。 /// 该rewriterfactoryhandler检查重写规则重写路径,如果需要的话,然后代表处理ASP.NET页责任到 /// pageparser (同一类由 pagehandlerfactory 类使用)。 /// </summary> public class RewriterFactoryHandler : IHttpHandlerFactory { /// <summary> /// 那么GetHandler由ASP.NET管道后相关的HttpModules跑。的工作那么GetHandler是返回一个HttpHandler可以处理该页的一个实例。 /// </summary> /// <param name="context">这是一个请求HttpContext</param> /// <param name="requestType">的HTTP数据传输方法(<b>得到</b>或<b>后</b>)</param> /// <param name="url">所请求的资源rawurl</param> /// <param name="pathTranslated">所请求的资源的物理路径</param> /// <returns>实现IHttpHandler的实例;具体地说,一个HttpHandler实例返回由<b> pageparser /// </b>类,这是默认的ASP.NET pagehandlerfactory代表同一类对。</returns> public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) { //日志信息的跟踪对象。 context.Trace.Write("RewriterFactoryHandler", "Entering RewriterFactoryHandler"); string senderToURL = url; string filePath = pathTranslated; //获取配置规则 RewriterRuleCollection rules = RewriterConfiguration.GetConfig().Rules;//该方法是读取web.config配置文件中取规则集合,并且使用了cache缓存以避免频繁IO操作 //遍历规则 for (int i = 0; i < rules.Count; i++) { string lookFor = "^" + RewriterUtils.RewriterUrl(context.Request.ApplicationPath, rules[i].LookFor) + "$"; //创建一个正则表达式对象的情况下,忽略了… Regex reg = new Regex(lookFor, RegexOptions.IgnoreCase); //看看我们找到一个匹配 if (reg.IsMatch(url)) { //做任何需要更换 senderToURL = RewriterUtils.RewriterUrl(context.Request.ApplicationPath, reg.Replace(url, rules[i].SenderTo)); //日志信息的跟踪对象… context.Trace.Write("RewriterFactoryHandler", "Found match, rewriting to " + senderToURL); //重写路径,得到更少的URL和查询字符串的物理文件路径 string senderToUrlLessQString = string.Empty; RewriterUtils.RewriterUrl(context, senderToURL, out senderToUrlLessQString, out pathTranslated); //返回的页面编译的版本 context.Trace.Write("RewriterFactoryHandler", "Exiting RewriterFactoryHandler");//日志信息的跟踪对象… return PageParser.GetCompiledPageInstance(url, filePath, context); } } //如果我们达到这一点,我们没有找到一个改写比赛 context.Trace.Write("RewriterFactoryHandler", "Exiting RewriterFactoryHandler");//日志信息的跟踪对象… return PageParser.GetCompiledPageInstance(url, filePath, context); } public virtual void ReleaseHandler(IHttpHandler handler) { } } }
using System; using System.Collections.Generic; using System.Linq; using System.Web; namespace ElToolsTest.URLWriter { /// <summary> /// 提供用于重写Web应用和HttpHandler实用的辅助方法。 /// 这类标记为内部,意义在同一组件只有类可以访问它的方法 /// </summary> internal class RewriterUtils { /// <summary> /// 重写的URL使用HttpContext。rewriteurl() /// </summary> /// <param name="context">HttpContext对象重写URL。</param> /// <param name="senderToUrl">URL重写。</param> internal static void RewriterUrl(HttpContext context, string senderToUrl) { string x, y; RewriterUrl(context, senderToUrl, out x, out y); } /// <summary> /// 重写的URL使用 HttpContext。rewriteurl() /// </summary> /// <param name="context">HttpContext对象重写URL。</param> /// <param name="senderToUrl">URL重写。</param> /// <param name="senderToUrlLessQstring">返回sendertourl剥离的查询字符串值</param> /// <param name="param name="filePath"">返回所请求页面的物理文件路径</param> internal static void RewriterUrl(HttpContext context, string senderToUrl, out string senderToUrlLessQstring, out string filePath) { //看看我们是否需要添加任何额外的查询字符串信息 if (context.Request.QueryString.Count > 0) { if (senderToUrl.IndexOf("?") != -1) { senderToUrl += "@" + context.Request.QueryString.ToString(); } else { senderToUrl += "?" + context.Request.QueryString.ToString(); } } //第一条查询字符串,如 string queryString = string.Empty; senderToUrlLessQstring = senderToUrl; if (senderToUrl.IndexOf('?') > 0) { senderToUrlLessQstring = senderToUrl.Substring(0, senderToUrl.IndexOf('?')); queryString = senderToUrl.Substring(senderToUrl.IndexOf('?') + 1); } //获取文件的物理路径 filePath = string.Empty; filePath = context.Server.MapPath(senderToUrlLessQstring); //重写路径 context.RewritePath(senderToUrlLessQstring, string.Empty, queryString); /* 注!上述rewritepath()过载只能在。NET框架1.1 如果您使用的是。NET框架1,使用下面的表格代替: 语境rewritepath(sendtourl); */ } /// <summary> /// 将URL到一个在请求客户端可用的。 /// 将~给请求的应用程序的路径。模仿的行为 /// 控制。resolveurl() 方法,这往往是由控件开发人员使用。 /// </summary> /// <param name="appPath">应用程序路径</param> /// <param name="url"></param> /// <returns>一个解决的URL。如果输入参数URL 包含~,取代它的是与的 apppath 参数值。</returns> internal static string RewriterUrl(string appPath, string url) { if (url.Length == 0 || url[0] != '~') { return url;//在第一个字符的位置没有~,刚刚返回的URL } else { if (url.Length == 1) { return appPath;//只有在网址中的~,返回apppath } if (url[1] == '/' || url[1] == '\\') { //URL看起来像~ /或~ \ if (appPath.Length > 1) { return appPath + "/" + url.Substring(2); } else { return "/" + url.Substring(2); } } else { //~ URL看起来像什么 if (appPath.Length>1) { return appPath + "/" + url.Substring(1); } else { return "/" + url.Substring(1); } } } } } }
<?xml version="1.0" encoding="utf-8"?> <!-- 有关如何配置 ASP.NET 应用程序的详细消息,请访问 http://go.microsoft.com/fwlink/?LinkId=169433 --> <configuration> <configSections> <!-- < configsections >元素必须包含一个<第> 标签为< rewriterconfig >节元素。 本节处理程序类型是rewriterconfigserializersectionhandler,这是负责反序列化<rewriterconfig >节元素为rewriterconfig实例。 --> <section name="RewriterConfig" type="ElToolsTest.URLWriter.RewriterConfigSerializerSectionHandler"/> </configSections> <RewriterConfig> <Rules> <ReWriterRule> <LookFor>http://(www\.|)baidu.com/Login.htm</LookFor> <SenderTo><![CDATA[~/test.htm]]></SenderTo> </ReWriterRule> </Rules> </RewriterConfig> <system.web> <compilation debug="true" targetFramework="4.0" /> <httpHandlers> <add verb="*" path="*.html" type="ElToolsTest.URLWriter.RewriterFactoryHandler"/> </httpHandlers> <httpModules> <add name="ModeRewriter" type="ElToolsTest.URLWriter.ModeRewriter" /> </httpModules> </system.web> </configuration>
代码里有变量可以自己变更即可。若有不对之处还请指出,谢谢!