• Discuz!NT 的URL地址重写(URLRewrite)


          声明:本文内容纯属个人观点,官方保留最终解释   

          在Discuz!NT中的前台页面访问(特别是aspx)是被HttpModule接管的,所以大家在Discuz.Web
    项目的目录下看到的唯一"aspx文件"是index.aspx,而所有其它前台页面都有“/aspx/”文件夹下的相应
    的子目录中,而这些子目录名称是与后台所“生成”的模板存在对应关系的。而这种“关系”的绑定是通
    过dnt_templates(模板数据表)来进行关联的。而有关模板机制的文章详见:

        “Discuz!NT 模板机制分析”一文。

         今天所要说的其实是模板机制的“延续”,当然这种“延续”仅是我个人的观点。因为地址重写最终
    要绑定的路径,恰恰与模板机制是有着前后呼应的关系。首先请大家看一下这张图:

            
         图1 :[discuz!NT 的web.config文件相关配置节]
        

          相信对于那些以前做过“URL重写”的朋友看到这一行配置的第一反映可能就是要去Discuz.Forum
    .HttpModule类中一看究竟。同时考虑到在<httpModules>配置节中加入处理的资料在网上有许多,所
    以这里就不再多费唇舌了。

          另外如果大家感兴趣味的话,也可以抽空看看我的这篇文章,"NET框架中的 Observer 模式"。虽
    然该文是我在挖.net底层代码时是写的一些个人想法,可读性不高,但我相信会对大家有所帮助的:)

          好了,下面让我们看一下在Discuz.Forum项目中的HttpModule类中的一些信息,看看URL重写到
    底如何实现:)
       

     1/// <summary>
     2 /// 论坛HttpModule类
     3 /// </summary>

     4 public class HttpModule : System.Web.IHttpModule
     5 {
     6         /// <summary>
     7  /// 实现接口的Init方法
     8  /// </summary>
     9  /// <param name="context"></param>

    10  public void Init(HttpApplication context)
    11  {
    12    OnlineUsers.ResetOnlineList();
    13   context.BeginRequest += new EventHandler(ReUrl_BeginRequest);
    14  }

    15
    16 
    17

    18

          上面代码中的Init(HttpApplication context)是HttpModule类进行操作的入口,所有实现
    System.Web.IHttpModule 接口的类都必须实现这个函数。
         同时大家看到的OnlineUsers.ResetOnlineList()方法主要是用于“重置(复位)在线表”,
    而有关“在线用户”的功能我会在以后专门写文章来加以介绍,所以这里大家只要知道它要干的
    事(代码如下)即可:)

            

     1  /// <summary>
     2  /// 复位在线表, 如果系统未重启, 仅是应用程序重新启动, 则不会重新创建
     3  /// </summary>
     4  /// <returns></returns>

     5  public static int ResetOnlineList()
     6  {
     7   try
     8   {
     9    // 取得在线表最后一条记录的tickcount字段 (因为本功能不要求特别精确)
    10                //int tickcount = DatabaseProvider.GetInstance().GetLastTickCount();
    11    // 如果距离现在系统运行时间小于10分钟
    12    if (System.Environment.TickCount < 600000)
    13    {
    14     return InitOnlineList();
    15    }

    16    return -1;
    17   }

    18   catch
    19   {
    20    try
    21    {
    22     return InitOnlineList();
    23    }

    24    catch
    25    {
    26     return -1;
    27    }

    28   }

    29
    30  }

    31
    32


          而紧随其后的事件绑定代码就是一个关键点了,形如:
          

    context.BeginRequest += new EventHandler(ReUrl_BeginRequest);

          因为当通过浏览器提交请求时,IIS都会接管请求进行相应的操作(详见DUDU的文章:" ASP.NET 2.0运行时
    简要分析
    ")后,最终通过Web.config中的相应配置节(上图所示)来执行用户预定的处理操作。而我们的代码就
    ReUrl_BeginRequest事件中(代码如下,详情见注释):

            

     1/// <summary>
     2        /// 重写Url
     3        /// </summary>
     4  /// <param name="sender">事件的源</param>
     5  /// <param name="e">包含事件数据的 EventArgs</param>

     6  private void ReUrl_BeginRequest(object sender, EventArgs e)
     7  {
     8                        //获取基本配置信息
     9   BaseConfigInfo baseconfig = BaseConfigProvider.Instance();
    10            
    11   if (baseconfig == null)
    12          {
    13                  return;
    14              }

    15
    16                        //得到论坛配置信息
    17              GeneralConfigInfo config = GeneralConfigs.GetConfig();
    18   HttpContext context = ((HttpApplication)sender).Context;
    19   string forumPath = baseconfig.Forumpath.ToLower();
    20
    21   string requestPath = context.Request.Path.ToLower();
    22
    23   if (requestPath.StartsWith(forumPath))
    24   {
    25    if (requestPath.Substring(forumPath.Length).IndexOf("/"== -1)
    26    {
    27     // 声明并设置默认论坛模板
    28                   string strTemplateid = config.Templateid.ToString();
    29     // 判断COOKIE中模板是否是系统当前的有效(已入库)模板
    30                      if (Utils.InArray(Utils.GetCookie(Utils.GetTemplateCookieName()), 
    31      Templates.GetValidTemplateIDList()))
    32     {
    33                           strTemplateid = Utils.GetCookie(Utils.GetTemplateCookieName());
    34     }

    35
    36     //当访问的是首页时
    37                      if (requestPath.EndsWith("/index.aspx"))
    38                       {
    39      //当配置文件中未指定首页时,则将forumindex.aspx做为首页并重写路径
    40                           if (config.Indexpage == 0)
    41                           {
    42                                
    43                                context.RewritePath(forumPath + "aspx/" + strTemplateid + "/forumindex.aspx");
    44                           }

    45                           else //否则使用聚合首页来做为网站首页并重写路径
    46                           {
    47                                
    48                                context.RewritePath(forumPath + "aspx/" + strTemplateid + "/website.aspx");
    49                           }

    50
    51                           return;
    52                       }

    53
    54
    55                       //当使用伪aspx, 如:showforum-1.aspx等.
    56                       if (config.Aspxrewrite == 1)
    57                       {
    58      //获取后台设置的可以使用的伪aspx设置.
    59      //SiteUrls.GetSiteUrls()类和方法说明见下文
    60                           foreach (SiteUrls.URLRewrite url in SiteUrls.GetSiteUrls().Urls)
    61                           {
    62       //进行正则匹配,来看访问页面是否是用户定义的伪URL地址
    63                                if (Regex.IsMatch(requestPath, url.Pattern, Utils.GetRegexCompiledOptions() | RegexOptions.IgnoreCase))
    64                                {
    65                                    string newUrl = Regex.Replace(requestPath.Substring(context.Request.Path.LastIndexOf("/")), url.Pattern, url.QueryString, Utils.GetRegexCompiledOptions() | RegexOptions.IgnoreCase);
    66                                    
    67                                    context.RewritePath(forumPath + "aspx/" + strTemplateid + url.Page, string.Empty, newUrl);
    68                                    return;
    69                                }

    70                           }

    71                       }

    72
    73                       
    74                   
    75                       context.RewritePath(forumPath + "aspx/" + strTemplateid + requestPath.Substring(context.Request.Path.LastIndexOf("/")), string.Empty, context.Request.QueryString.ToString());
    76    }

    77    //当前请求路径是“论坛路径/archiver(简洁版路径)/"下时.
    78    else if (requestPath.StartsWith(forumPath + "archiver/"))
    79    {
    80                       
    81                       
    82                       return;
    83    }

    84     //当前请求路径是“论坛路径/tools/(论坛工具页面如:rss,sitemap,help等)”请求时
    85    else if (requestPath.StartsWith(forumPath + "tools/"))
    86    {
    87                       
    88                   return;
    89    }

    90
    91   }

    92  }

    93
    94

           这样就实现了伪URL的动态转换(地址重写)。而相应的“SiteUrls”类则是对伪URL设置信息
    进行访问读取的“封装类”,目的就是要将Discuz.Web项目中config文件夹下的urls.config文件转换
    成可访问的信息对象。形如:

     

      1/// <summary>
      2 /// 站点伪Url信息类
      3 /// </summary>

      4 public class SiteUrls
      5 {
      6  内部属性和方法
     66
     67                //获取伪URL设置对象的实例
     68  public static SiteUrls GetSiteUrls()
     69  {
     70   if (instance == null)
     71   {
     72    lock (lockHelper)
     73    {
     74     if (instance == null)
     75     {
     76      instance = new SiteUrls();
     77     }

     78    }

     79   }

     80   return instance;
     81
     82  }

     83
     84  public static void SetInstance(SiteUrls anInstance)
     85  {
     86   if (anInstance != null)
     87    instance = anInstance;
     88  }

     89
     90  public static void SetInstance()
     91  {
     92   SetInstance(new SiteUrls());
     93  }

     94
     95                
     96  /// <summary>
     97  /// 重写伪地址(内部类),用于声明和封装对象
     98  /// </summary>

     99  public class URLRewrite
    100  {
    101   成员变量 
    154
    155   构造函数
    164  }

    165
    166 }

    167
    168

           因为代码很简单,这里就不再另行说明了。

           到目前,我们知道了要通过“urls.config”文件来进行伪URL重写,那么这个文件中的数据到底是什么
    样子呢,下面就是在成功安装discuz!nt 2.0产品之后的文件内容:

    <?xml version="1.0" encoding="utf-8" ?> 
    <urls>
         
    <rewrite name="showforum"
              path
    ="/showforum-{0}-{1}.aspx"
              pattern 
    = "/showforum-(\d+)(-(\d+))?.aspx"
              page
    ="/showforum.aspx"
              querystring
    ="forumid=$1^page=$3" />
        
    <rewrite name="showtopic"
              path
    ="/showtopic-{0}-{1}.aspx"
              pattern 
    = "/showtopic-(\d+)(-(\d+))?.aspx"
              page
    ="/showtopic.aspx"
              querystring
    ="topicid=$1^page=$3" />
        
    <rewrite name="userinfo"
              path
    ="/userinfo-{0}.aspx"
              pattern 
    = "/userinfo-(\d+)*.aspx"
              page
    ="/userinfo.aspx"
              querystring
    ="userid=$1" />
         
    <rewrite name="rss"
              path
    ="/rss-{0}.aspx"
              pattern 
    = "/rss-(\d+)?.aspx"
              page
    ="/rss.aspx"
              querystring
    ="forumid=$1" />
         
    <rewrite name="spacerss"
              path
    ="/spacerss-{0}.aspx"
              pattern
    ="/spacerss(-(\d+))?.aspx(\?.*?)?"
              page
    ="/rss.aspx"
              querystring
    ="uid=$2&amp;type=space" />
         
    <rewrite name="photorss"
              path
    ="/photorss-{0}.aspx"
              pattern
    ="/photorss(-(\d+))?.aspx(\?.*?)?"
              page
    ="/rss.aspx"
              querystring
    ="uid=$2&amp;type=photo" />
    </urls>

         大家看到了吧。就目前而言伪URL重写的页面(page节点)包括如下几个:

         showforum.aspx(版块列表),showtopic.aspx(主题列表),userinfo.aspx(用户信息),rss.aspx,
    虽然不多,但已基本满足了设置需要。

         而设置(配置)管理的页面在后台的“全局”-->“常规选项”-->“基本设置”-->“编辑伪静态url替换
    规则”,如果所示:




         相信聊到这里大家对我们产品的这项功能应该有个大概认识了,但这不并是全部的设置,因为如果要接管
    形如"showforum-1-2.htm"这样的页面,是必须要到IIS里去“搞一把”的。因为默认的IIS中对htm(html)
    的处理是无法实现将上面的链接转成“showforum.aspx?forumid=1&page=2”的形式的,所以这里要参考
    一下官方文档(使用伪Url地址中的方法,相应图示如下:

            


        

          好的,下面再接着聊一下关于与第三方产品“整和”的问题。因为目前大多数采用 .net技术开发的主流产品
    (如博客园等)都会或多或少使用与本文类似或相同的做法来实现地址重写功能。比如:继承并实现IHttpHandler
    接口。
     
          当然我们的产品所采用实现IHttpModule的方式会比IHttpHandler更早一步被 IIS进行处理。所以如果出现
    了这种情况,我个人建议是改动我们产品中的代码,通过在上述 ReUrl_BeginRequest事件中加入条件分支(第
    三方程序的伪地址规则)来实现“地址重写整合”;当然如果第三方的 (重写)规则太复杂的话,也可以在我们产
    品的相应代码中加入条件分支(只要出现第三方请求的链接页面或指定路径时),但不作任何处理(直接绿灯放行
    ),这样就会转入到第三方的伪URL重写规则代码的“势力范围”内了。

         当然如果第三方也使用类似IHttpModule的实现方式,则要看是谁的配置先出现在web.config中的相应配置
    节中了。因为“先入为主”嘛,如果先后顺序已明确的话,那么先被加载的HttpModule 模块就要做一下变动了,
    以便不会干扰后面的HttpModule模块的正常运行了。因为我手上这方面的实例也不多,所以只能在这里聊聊我本
    人的一些看法,相信随着官方“整合案例” 的增加,这方面的资料会得到更大的补充。

          好了,今天就先聊到这吧,如果大家有什么问题,欢迎与我交流:)

          我的email:  daizhj@discuz.com,  daizhj617595@126.com, daizhj@gmail.com

          关键字:.net,discuz,disucznt,httpmodule,HttpHandler,RewritePath,地址重写


     


  • 相关阅读:
    jq:翻页时,保存上页多选框checkbox选中状态
    SpringMVC日期类型转换问题处理方法归纳
    SpringMVC的Date与String互转
    使用AJAX异步提交表单的几种方式
    ORACLE——日期时间格式化参数详解 之三
    ORACLE——日期时间格式化参数详解 之一
    ORACLE——日期时间格式化参数详解 之二
    Json-lib 进行java与json字符串转换之二
    Json-lib 进行java与json字符串转换之一
    java继承-子类调用父类的方法中包含子类重写的方法
  • 原文地址:https://www.cnblogs.com/daizhj/p/1034103.html
Copyright © 2020-2023  润新知