好像在Apache上用Apache的mod_rewrite,配置一下就可以轻松的解决问题了。据说微软的IIS7中也支持了这种特性,IIS7可以在 IIS 请求管道的任何地方执行一个HttpModule,下面是IIS7给的配置:
<?xml version="1.0" encoding="UTF-8"?> <configuration> <configSections> <section name="rewriter" requirePermission="false" type="Intelligencia.UrlRewriter.Configuration.RewriterConfigurationSectionHandler, Intelligencia.UrlRewriter" /> </configSections> <system.web> <httpModules> <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule, Intelligencia.UrlRewriter" /> </httpModules> </system.web> <system.webServer> <modules runAllManagedModulesForAllRequests="true"> <add name="UrlRewriter" type="Intelligencia.UrlRewriter.RewriterHttpModule" /> </modules> <validation validateIntegratedModeConfiguration="false" /> </system.webServer> <rewriter> <rewrite url="~/products/(.+)" to="~/products.aspx?category=$1" /> </rewriter> </configuration> |
遗憾的是服务器使用的是Win2003+IIS6。并且服务器上同时部署了asp程序和asp.net
程序如果使用 UrlRewriter.net组件,只能在HttpModule一级重写,只能作用于所有使用 % WINDIR
%/Microsoft.NET/Framework/v2.0.50727/aspnet_isapi.dll处理请求的后缀文件。如 .aspx
.ascx请求。但是asp是用%WINDIR%/WINDOWS/system32/inetsrv/asp.dll来处理请求的。请求不会分检到
Asp.net的HttpModule中。所以对于asp的请求,UrlRewriter.net组件的HttpModule重写不能起效。.jpg
.gif .htm也不能被重写。看来只能用ISAPI Filters http://msdn2.microsoft.com/en-us/library/ms525908.aspx 来重写了。
SAPI Filters有两个非常著名工程:
1. Helicon Techs ISAPI Rewrite: http://www.isapirewrite.com/ 提供一个99美元(可免费试用30天)的ISAPI URL重写产品完整版,以及一个免费的轻量级版本。
2. Ionics ISAPI Rewrite: http://cheeso.members.winisp.net/IIRF.aspx 全免费开源组件。
Helicon Techs ISAPI Rewrite的产品完整版已经解决了这个问题。可是Helicon Techs的付费手段少,在付费线购买太难用了,如果像支付宝一样好用(点击付款连再次确认都没有,直接钱就出去了 呵呵)估计会增加购买量。
看来自己动手丰衣足食的时候到了,从Ionics ISAPI Rewrite的基础上改一个可以支持二级域名重写的ISAPI Filter吧。下载Ionics Isapi Rewrite Filter(下面简写为IIRF) http://www.codeplex.com/IIRF/Release/ProjectReleases.aspx?ReleaseId=5018 。最后一个版本是1.2.12c Beta 千万不要用1.2.12b,1.2.12b有内存泄露问题。1.2.12c修复了这个问题(加了free( myCopy )部分的代码)。
下
载后主要有8 个文件。IsapiRewrite4.c TestDriver.c IirfConfig.h IirfConstants.h
IirfRequestContext.h RewriteRule.h pcre-5.0/ pcre.h pcre-5.0/pcre.lib
其中的TestDriver.c是测试正则表达式的exe可以先不看。RewriteRule.h pcre-5.0/ pcre.h
pcre-5.0/pcre.lib 是正则表达式解析引擎。
修改makefile中:VC="C:/Program
Files/Microsoft Visual Studio 8/VC"
和PCRESOURCE=E:/Project/InUrlRewrite/SRC/pcre-5.0 部分。到.net
2.0的console下cd进入下载目录使用 nmake –f makefile编译。让工程可以正确编译。
搭建一个可以测试自己编
译的ISAPI Filter的环境。建一个WebSite在ISAPI
Filters添加刚刚Build好的IsapiRewrite4.dll。重启IIS。在IsapiRewrite4.ini中设置输出Log等级为
5(输出详细Log)指定Log输出位置。修改%WINDIR%/system32/drivers/etc/hosts文件。在域名解析中加入
127.0.0.1 abc.company.com 和 127.0.0.1
company.com这两行便于测试。在新建的WebSite中加入一个test.asp文件,test.asp中只用写
Response.Write(Query("Domain")) 提供重写后的测试。
到这里所有的编程前需要的环境都部署好了。现在可
以开始改
IIFR了。看完了所有的代码,发现核心的内容都在IsapiRewrite4.c中,这个文件总共有2600多行。核心的函数是DoRewrites。
对外的Entry-Point Functions是GetFilterVersion HttpFilterProc
TerminateFilter通过这三个方法向IIS暴露 ISAPI Filter内部的功能,IIS会调用ISAPFilter的这三个方法。在http://msdn2.microsoft.com/en-us/library/ms525572.aspx 中有详细的介绍。
主要修改DoRewrites就基本上可以满足要求了。
1. 添加一个新的表示Pattern -> [D]。
2. 修改ApplyRules方法对Url的处理,当表示Pattern是[D]时,从GetServerVariable("HTTP_HOST", pfc)中取得http_host,拼凑到OriginalUrl前再进行正则表达式的匹配。
经过上面两部就实现了对二级域名重写的功能。
注意:IIFR的License要求(在IsapiRewrite4.c顶部有详细的描述)很严格。可能不允许再生产,和商业使用。
修改后的工程:
1.修改RewriteRule.h 在RewriteRule结构体中加入 boolean IsMatchDomain 这个Field标识新的Pattern. 修改后的结构:
typedef struct RewriteRule { pcre * RE; char * Pattern; char * Replacement; boolean IsRedirect; int RedirectCode; boolean IsForbidden; boolean IsNotFound; boolean IsLastIfMatch; boolean IsCaseInsensitive; boolean RecordOriginalUrl; boolean IsMatchDomain; // any condition that applies // doubly-linked list |
2.修改IsapiRewrite4.c中的ParseRuleModifierFlags方法加入对IsMatchDomain的处理。修改后的方法:
void ParseRuleModifierFlags(char * pModifiers, RewriteRule *rule) { char MsgBuffer[512]; rule->IsRedirect= FALSE; if (pModifiers==NULL) return; // no flags at all sprintf_s(MsgBuffer,512,"ParseRuleModifierFlags: %s", pModifiers); if ((pModifiers[0] != [) || p2= strtok_s(p1, ",", &StrtokContext); // split by commas if (p2[0]==R) { // redirect p2= strtok_s(NULL, ",", &StrtokContext); // next token // consistency checks } |
3.修改IsapiRewrite4.c中的ApplyRules方法加入对请求中httphost部分的处理。修改后的方法:
int ApplyRules( HTTP_FILTER_CONTEXT * pfc, char * subject, int depth, /* out */ char **result, /* out */ boolean *pRecordOriginalUrl ) { RewriteRule * current= config->rootRule; int retVal= 0; // 0 = do nothing, 1 = rewrite, 403 = forbidden, other = redirect char MsgBuffer[512]; int c=0; int RuleMatchCount, i; int *RuleMatchVector; #if _WRITE_LOG sprintf_s(MsgBuffer,512,"ApplyRules (depth=%d)", depth); LogMsg(3, MsgBuffer); #endif if (current==NULL) { #if _WRITE_LOG LogMsg(2, "ApplyRules: No configuration available."); #endif return 0; } // The PCRE doc says vector length should be 3n?? why? seems like it ought to be 2n. or maybe 2n+1. // The way it works: First we evaluate the URL request, against the RewriteRule pattern. // TODO: employ a MRU cache to map URLs LogMsg(3, "subject"); RuleMatchCount = pcre_exec( // return code: >=0 means number of matches, <0 means error if (RuleMatchCount < 0) { PcreMatchResult RuleMatchResult; // The fields in CondMatchResult may be filled by the EvaluateConditionList(), but // evaluate the condition list, if there is one. // Check that any associated Condition evaluates to true, before char *ts1; // generate the replacement string // step 1: substitute back-references as appropriate. if (sizeof(MsgBuffer)-28> strlen(newString)) { // set output params // if the current rule asks to record the original URL, then set the OUT flag. // check modifiers break; // break out of while loop on the first match } // We did not break out of the loop. free(RuleMatchVector); |