在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
而緊隨其後的事件繫結程式碼就是一個關鍵點了,形如:
因為當通過瀏覽器提交請求時,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產品之後的檔案內容:
大家看到了吧。就目前而言偽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模組的正常執行了。因為我手上這方面的例項也不多,所以只能在這裡聊聊我本 人的一些看法,相信隨著官方“整合案例” 的增加,這方面的資料會得到更大的補充。
写评论
很抱歉,必須登入網站才能發佈留言。