利用ISAPI Filter“域名重写”实现完整的URL转发
// by redice 2009.8.21// http://www.
// 想写点东西...
背景知识:域名解析中“传统URL转发”是不完整的,只能转发到特定的URL,而不能转发到特定URL下的其它目录和文件。
示例一:
我们将域名bbs.做“传统URL转发”到http://www.。这样我们通过访问http://bbs. 就能访问到
http://www.的页面。但是我们不能通过http://bbs.
来访问 http://www.。因为“传统URL”转发只能转发到特定URL,而不能转发到其下的目录和文件。
示例二:
公益组织“慈善厨房”的国际域名是www.,它们的虚拟主机是国外的,这家IDC的虚拟主机不支持绑定多个域名(只能绑定一个域名,呵呵,不知道用的什么服务器)。现在“慈善厨房”又申请了一个cn域名:test.。他们想实现通过两个域名能访问到同样的内容,而且Web服务器必须要使用国外的那台虚拟主机。
“慈善厨房”将域名test.做URL转发到www.,这样通过test.可以访问到www.了。他们在中国对外公布了很多以test.为域名的子网页,
例如 http://test.(chn).asp,但是由于test.不能转发www.下的子目录和子网页,因此那些地址都是无效的。
如何解决上面的问题呢?
我们需要一种能实现完整URL转发的机制。我想到了使用ISAPI Filter“域名重写”实现完整的URL转发。
(“域名重写”这个词可是我创造的,哈哈)。
实现其实很简单,只需要3步:(我们需要准备一个虚拟主机,新建一个呗,就叫“慈善厨房”吧)
(1)在Win2003 IIS 6.0下新建一个虚拟主机,称为“慈善厨房”,将域名test.绑定其上。
(2)test.做域名解析到202.117.112.10(上面“慈善厨房”虚拟主机使用的IP)。
(3)核心:安装“域名重写”的ISAPI Filter插件。
ok,这样就成功了。前两步都很简单。关键是第三步,我们要编写一个ISAPI Filter实现“域名重写”。
熟悉Filter的人都知道,在SF_NOTIFY_URL_MAP事件处理过程中,我们可以很方便地获取到host,url,querystring这些信息,
这三个信息也就组成了一个完整的URL。只要我们将host替换成www.,然后使用ServerSupportFunction向
客户端发送"302 Redirect" URL重定向(重定向到我们新合成的完整URL),这样我们就实现了“域名重写”。
核心代码如下:
程序代码:
DWORD CSurFilter::OnUrlMap(CHttpFilterContext* pCtxt, PHTTP_FILTER_URL_MAP pMapInfo) { CString csNewFullUrl; // 新的完整地址 char szHost[256]={0}; CString csHost; DWORD dwLen=255; // 取得host if(pCtxt->GetServerVariable("HTTP_HOST",szHost,&dwLen)) { csHost=szHost; csHost.MakeLower(); this->ODS("host=%s\n",szHost); // 检查是否为需要重写的域名 if(csHost==this->csOldDomain) //csOldDomain为原域名,从配置文件中读取 { csNewFullUrl="Location: "; csNewFullUrl+="http://"+this->csNewDomain; //csNewDomain为新域名,从配置文件中读取 // 取得url this->ODS("url=%s\n",pMapInfo->pszURL); csNewFullUrl+=pMapInfo->pszURL; char szQueryString[256]={0}; dwLen=255; // 取得QueryString if(pCtxt->GetServerVariable("QUERY_STRING",szQueryString,&dwLen)) { if(strlen(szQueryString)>0) { this->ODS("querystring=%s\n",szQueryString); csNewFullUrl+="?"; csNewFullUrl+=szQueryString; } } this->ODS("NewFullUrl=%s\n",csNewFullUrl); csNewFullUrl+="\r\n\r\n"; // URL 重定向 pCtxt->ServerSupportFunction(SF_REQ_SEND_RESPONSE_HEADER, (LPVOID) "302 Redirect", (DWORD *) csNewFullUrl.GetBuffer(0),0); } } else this->ODS("获取host信息失败!\n"); return SF_STATUS_REQ_NEXT_NOTIFICATION; }通过上面三步设置,我们现在就可以通过“http://test.子目录/子页面"”
访问到“www.子目录/子页面”了。这样就实现了完整的URL转发。