利用ISAPI Filter“域名重写”实现完整的URL转发

// by redice 2009.8.21
// http://www.redicecn.cn/blogview.asp?Content_Id=185
// 想写点东西…

背景知识:域名解析中“传统URL转发”是不完整的,只能转发到特定的URL,而不能转发到特定URL下的其它目录和文件。

示例一:
我们将域名bbs.taoyard.com做“传统URL转发”到http://www.taoyard.com/bbs。这样我们通过访问http://bbs.taoyard.com 就能访问到
http://www.taoyard.com/bbs的页面。但是我们不能通过http://bbs.taoyard.com/index.asp?boardid=1
来访问 http://www.taoyard.com/bbs/index.asp?boardid=1。因为“传统URL”转发只能转发到特定URL,而不能转发到其下的目录和文件。

示例二:
公益组织“慈善厨房”的国际域名是www.yellowrivercharity.com,它们的虚拟主机是国外的,这家IDC的虚拟主机不支持绑定多个域名(只能绑定一个域名,呵呵,不知道用的什么服务器)。现在“慈善厨房”又申请了一个cn域名:test.soupkitchen.cn。他们想实现通过两个域名能访问到同样的内容,而且Web服务器必须要使用国外的那台虚拟主机。

“慈善厨房”将域名test.soupkitchen.cn做URL转发到www.yellowrivercharity.com,这样通过test.soupkitchen.cn可以访问到www.yellowrivercharity.com了。他们在中国对外公布了很多以test.soupkitchen.cn为域名的子网页,
例如 http://test.soupkitchen.cn/chinese/about(chn).asp,但是由于test.soupkitchen.cn不能转发www.yellowrivercharity.com下的子目录和子网页,因此那些地址都是无效的。

如何解决上面的问题呢?
我们需要一种能实现完整URL转发的机制。我想到了使用ISAPI Filter“域名重写”实现完整的URL转发。
(“域名重写”这个词可是我创造的,哈哈)。

实现其实很简单,只需要3步:(我们需要准备一个虚拟主机,新建一个呗,就叫“慈善厨房”吧)
(1)在Win2003 IIS 6.0下新建一个虚拟主机,称为“慈善厨房”,将域名test.soupkitchen.cn绑定其上。
(2)test.soupkitchen.cn做域名解析到202.117.112.10(上面“慈善厨房”虚拟主机使用的IP)。
(3)核心:安装“域名重写”的ISAPI Filter插件。

ok,这样就成功了。前两步都很简单。关键是第三步,我们要编写一个ISAPI Filter实现“域名重写”。

熟悉Filter的人都知道,在SF_NOTIFY_URL_MAP事件处理过程中,我们可以很方便地获取到host,url,querystring这些信息,
这三个信息也就组成了一个完整的URL。只要我们将host替换成www.yellowrivercharity.com,然后使用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.soupkitchen.cn/子目录/子页面””
访问到“www.yellowrivercharity.com/子目录/子页面”了。这样就实现了完整的URL转发。

发表评论

您的电子邮箱地址不会被公开。