因為一些原因,要將原來兩個獨立的站點(假設為dh.site.com和cd.site.com)放到同一個站點的兩個application下,分別為(www.site.com/dh和www.site.com/cd)。
因為在開發的時候,大部分靜態文件的引用路徑都是采用絕對路徑的形式,例如/style/css1.css。可想而知,當將兩個站點作為兩個application放置后,這些靜態文件就變得無法訪問了,因為文件真實的路徑已經變成了/dh/style.css1.css了。解決這個問題的最直接的方法就是修改所有的絕對路徑:要么將原來的路徑加上application的虛擬根路徑(例如將/style.css1.css變成/dh/style.css1.css),要么改成相對路徑。但無論如何,直接修改路徑的方式都要找出散布在各個角落里的路徑查找出來,再進行修改。雖然利用IDE的查找替換功能可以很快將路徑查找出來,但也難免查找不完全,另一方面,如果路徑數量非常多,則不得不花費大量時間去修改並且在修改后進行檢查排錯。
嘗試一:使用http module進行路徑重寫。
這也是非常直接地聯想到的方法:使用http module(可以使用url rewriter,或者自己編寫一個http module)對正在進行訪問的url進行重寫到正確的路徑。但這使用http module進行重寫會有一個問題:只能用作重寫靜態文件請求,而對於aspx之類的動態文件的請求,因為在IIS6或以上,不同應用程序運行在不同的應用程序域(app domain)中,因此對動態文件的請求進行重寫轉跳,會發現兩個轉跳對象的session根本不同,或者根本不能加載類型(root application可以加載子application的類型)。這無論從網站安全角度,還是程序都安全角度來說,都是合理的。
因為這里需要自定義更多的東西,因此需要自己編寫一個http module,而不是使用url rewriter。思路如下:因為cd和dh中的靜態文件都是指向到虛擬根目錄的,因此需要在站點的root application中使用該http module。而在http module中,根據靜態文件請求的referrer來判斷請求時來自dh還是cd,然后再重定向到dh或者cd下相對應的文件。
http module中的代碼:
public class RedirectModule : IHttpModule { //定義靜態文件的擴展名數組 static string[] staticsFilesExName=new string[]{".jpg",".jepg",".gif",".png",".css",".html",".js"}; void context_BeginRequest(object sender, EventArgs e) { HttpApplication app = sender as HttpApplication; if (app.Context.Request.UrlReferrer != null) { //取得頁面的referrer,進行判斷請求是來自www.site.com/dh還是來自www.site.com/cd string referrer = app.Context.Request.UrlReferrer.AbsoluteUri; //取得application root path部分,也就是http://www.site.com/dh中的"/dh"部分 string appRootPath = referrer.Substring(23, 3); string rawUrl = app.Request.RawUrl; //得到轉跳的url string reUrl = appRootPath + rawUrl; string extendName = app.Request.Path.Substring(app.Request.Path.LastIndexOf(".")); //判斷請求的對象是否為靜態文件,是則轉跳。 if (RedirectModule.staticsFilesExName.Contains(extendName.ToLower())) { app.Context.RewritePath(reUrl); } } } public void Dispose() { } public void Init(HttpApplication context) { context.BeginRequest += new EventHandler(context_BeginRequest); } }
注:在IIS7.5中,為了能使http module正常工作,除了在web.config/httpModules節下添加http module外,必須將站點的應用程序池版本.net framework版本設置為V2.0,並且將托管管道模式設置經典(classic),此外,還可能需要在system.webServer/handlers節中添加配置:
<add name="wildcard" path="*" verb="*" modules="IsapiModule" scriptProcessor="%windir%\Microsoft.NET\Framework\v2.0.50727\aspnet_isapi.dll" resourceType="Unspecified" requireAccess="None" preCondition="classicMode,runtimeVersionv2.0,bitness32" />
然而,雖然使用http module能解決靜態文件訪問的問題,但不能重寫動態文件,所以這不是個完美的解決方案。當然,如果動態文件的url數量少,手動改起來工作也不大的話,這也是個可以接受的方法。
另外,可以考慮一下使用isapi filter來實現請求url重寫,而且因為不同於http module要受到.net的限制,isapi filter運行在IIS層次之中,是否能突破應用程序池的限制,重定向的文件能順利被執行(就如同該請求事來自瀏覽器一樣)?