|
aspx1
|
2008-03-29 22:33
| 只看楼主
树型|
收藏|
小
中
大
1#
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 内部属性和方法#region 内部属性和方法 7 private static object lockHelper = new object(); 8 private static volatile SiteUrls instance = null; 9 10 string SiteUrlsFile = HttpContext.Current.Server.MapPath(BaseConfigs.GetForumPath + "config/urls.config"); 11 private System.Collections.ArrayList _Urls; 12 public System.Collections.ArrayList Urls 13 { 14 get 15 { 16 return _Urls; 17 } 18 set 19 { 20 _Urls = value; 21 } 22 } 23 24 private System.Collections.Specialized.NameValueCollection _Paths; 25 public System.Collections.Specialized.NameValueCollection Paths 26 { 27 get 28 { 29 return _Paths; 30 } 31 set 32 { 33 _Paths = value; 34 } 35 } 36 37 private SiteUrls() 38 { 39 Urls = new System.Collections.ArrayList(); 40 Paths = new System.Collections.Specialized.NameValueCollection(); 41 42 XmlDocument xml = new XmlDocument(); 43 44 xml.Load(SiteUrlsFile); 45 46 XmlNode root = xml.SelectSingleNode("urls"); 47 foreach(XmlNode n in root.ChildNodes) 48 { 49 if (n.NodeType != XmlNodeType.Comment && n.Name.ToLower() == "rewrite") 50 { 51 XmlAttribute name = n.Attributes["name"]; 52 XmlAttribute path = n.Attributes["path"]; 53 XmlAttribute page = n.Attributes["page"]; 54 XmlAttribute querystring = n.Attributes["querystring"]; 55 XmlAttribute pattern = n.Attributes["pattern"]; 56 57 if (name != null && path != null && page != null && querystring != null && pattern != null) 58 { 59 Paths.Add(name.Value, path.Value); 60 Urls.Add(new URLRewrite(name.Value, pattern.Value, page.Value.Replace("^", "&"), querystring.Value.Replace("^", "&"))); 61 } 62 } 63 } 64 } 65 #endregion 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 成员变量#region 成员变量 102 private string _Name; 103 public string Name 104 { 105 get 106 { 107 return _Name; 108 } 109 set 110 { 111 _Name = value; 112 } 113 } 114 115 private string _Pattern; 116 public string Pattern 117 { 118 get 119 { 120 return _Pattern; 121 } 122 set 123 { 124 _Pattern = value; 125 } 126 } 127 128 private string _Page; 129 public string Page 130 { 131 get 132 { 133 return _Page; 134 } 135 set 136 { 137 _Page = value; 138 } 139 } 140 141 private string _QueryString; 142 public string QueryString 143 { 144 get 145 { 146 return _QueryString; 147 } 148 set 149 { 150 _QueryString = value; 151 } 152 } 153 #endregion
154 155 构造函数#region 构造函数 156 public URLRewrite(string name, string pattern, string page, string querystring) 157 { 158 _Name = name; 159 _Pattern = pattern; 160 _Page = page; 161 _QueryString = querystring; 162 } 163 #endregion 164 } 165 166 } 167 168 因为代码很简单,这里就不再另行说明了。 到目前,我们知道了要通过“urls.config”文件来进行伪URL重写,那么这个文件中的数据到底是什么 样子呢,下面就是在成功安装discuz!nt 2.0产品之后的文件内容: <?xml version="1.0" encoding="utf-8" ?>
 |