RewriterURL实现二级域名的访问

     在这里与大家分享一下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>

 

代码里有变量可以自己变更即可。若有不对之处还请指出,谢谢!

posted @ 2014-06-10 21:12  KenyonLi  阅读(363)  评论(0编辑  收藏  举报