MVC實現動態二級域名


  前段時間,一個朋友問我ASP.NET MVC下實現動態二級域名的問題。跟他聊了一些解決方案,這里也總結一下,以供參考。

  相信大家都發現類似58同城這樣的網站,成都的網址是cd.58.com 上海的是sh.58.com類似的上千個網站,其實沒有那么多個網站,域名前面那部分就是泛域名解析,相當於是傳遞一個參數,所有的域名實際上訪問的都是一個網站,僅僅是傳遞了不一樣的參數顯示不一樣的內容。

  比如網站主域名入口為:www.58.com

  當成都的用戶登錄時,解析到:cd.58.com

  當上海的用戶登錄時,則解析到:sh.58.com

  首先想到的是對Url的重寫:(這在ASP.NET中也是常用的手法。網上有關於UrlRewrite的實現,這里不再重復。)

  還有就是MVC 應用程序中的典型URL模式,這里只討論MVC應用程序URL模式下的動態二級域名實現,測試實例下載

  1.定義DomainData、DomainRoute類

  public class DomainRoute : Route
  {
  private Regex domainRegex;
  private Regex pathRegex;

  public string Domain { get; set; }

  public DomainRoute(string domain, string url, RouteValueDictionary defaults): base(url, defaults, new MvcRouteHandler())
  {
    Domain = domain;
  }

  public DomainRoute(string domain, string url, RouteValueDictionary defaults, IRouteHandler routeHandler): base(url, defaults, routeHandler)

  {
    Domain = domain;
  }

  public DomainRoute(string domain, string url, object defaults): base(url, new RouteValueDictionary(defaults), new MvcRouteHandler())
  {
    Domain = domain;
  }

  public DomainRoute(string domain, string url, object defaults, IRouteHandler routeHandler): base(url, new RouteValueDictionary(defaults), routeHandler)
  {
    Domain = domain;
  }

  public override RouteData GetRouteData(HttpContextBase httpContext)
  {
    // 構造 regex
    domainRegex = CreateRegex(Domain);
    pathRegex = CreateRegex(Url);
    // 請求信息
    string requestDomain = httpContext.Request.Headers["host"];
    if (!string.IsNullOrEmpty(requestDomain))
    {
      if (requestDomain.IndexOf(":") > 0)
      {
        requestDomain = requestDomain.Substring(0, requestDomain.IndexOf(":"));
      }
    }
    else
    {
      requestDomain = httpContext.Request.Url.Host;
    }
    string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2) + httpContext.Request.PathInfo;

    // 匹配域名和路由
    Match domainMatch = domainRegex.Match(requestDomain);
    Match pathMatch = pathRegex.Match(requestPath);

    // 路由數據
    RouteData data = null;
    if (domainMatch.Success && pathMatch.Success)
    {
      data = new RouteData(this, RouteHandler);
      // 添加默認選項
      if (Defaults != null)
      {
        foreach (KeyValuePair<string, object> item in Defaults)
        {
          data.Values[item.Key] = item.Value;
        }
      }

      // 匹配域名路由
      for (int i = 1; i < domainMatch.Groups.Count; i++)
      {
        Group group = domainMatch.Groups[i];
        if (group.Success)
        {
          string key = domainRegex.GroupNameFromNumber(i);
          if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
          {
            if (!string.IsNullOrEmpty(group.Value))
            {
              data.Values[key] = group.Value;
            }
          }
        }
      }

      // 匹配域名路徑
      for (int i = 1; i < pathMatch.Groups.Count; i++)
      {
        Group group = pathMatch.Groups[i];
        if (group.Success)
        {
          string key = pathRegex.GroupNameFromNumber(i);

          if (!string.IsNullOrEmpty(key) && !char.IsNumber(key, 0))
          {
            if (!string.IsNullOrEmpty(group.Value))
            {
              data.Values[key] = group.Value;
            }
          }
        }
      }
    }

    return data;
  }

  public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
  {
    return base.GetVirtualPath(requestContext, RemoveDomainTokens(values));
  }

  public DomainData GetDomainData(RequestContext requestContext, RouteValueDictionary values)
  {
    // 獲得主機名
    string hostname = Domain;
    foreach (KeyValuePair<string, object> pair in values)
    {
      hostname = hostname.Replace("{" + pair.Key + "}", pair.Value.ToString());
    }

    // Return 域名數據
    return new DomainData
    {
      Protocol = "http",
      HostName = hostname,
      Fragment = ""
    };
  }

    private Regex CreateRegex(string source)
  {
    // 替換
    source = source.Replace("/", @"\/?");
    source = source.Replace(".", @"\.?");
    source = source.Replace("-", @"\-?");
    source = source.Replace("{", @"(?<");
    source = source.Replace("}", @">([a-zA-Z0-9_]*))");

    return new Regex("^" + source + "$", RegexOptions.IgnoreCase);
  }

  private RouteValueDictionary RemoveDomainTokens(RouteValueDictionary values)
  {
    Regex tokenRegex = new Regex(@"({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?({[a-zA-Z0-9_]*})*-?\.?\/?");
    Match tokenMatch = tokenRegex.Match(Domain);
    for (int i = 0; i < tokenMatch.Groups.Count; i++)
    {
      Group group = tokenMatch.Groups[i];
      if (group.Success)
      {
        string key = group.Value.Replace("{", "").Replace("}", "");
        if (values.ContainsKey(key))
          values.Remove(key);
      }
    }

    return values;
   }
  }
  public class DomainData
  {
    public string Protocol { get; set; }
    public string HostName { get; set; }
    public string Fragment { get; set; }
  }

 

  2.修改RouteConfig,增加如下代碼

    routes.Add(
      "DomainRoute", new DomainRoute(
      "{CityNameUrl}.weiz.com",
      "{controller}/{action}/{id}",
      new { CityNameUrl = "", controller = "City", action = "Index", id = "" }
    ));

  

  3.增加CityController控制類

public class CityController : Controller
  {
    public ActionResult Index()
    {
      var cityName = RouteData.Values["CityNameUrl"];
      ViewBag.CityName = cityName;
      return View();
    }
  }

 

  4.發布網站,並修改相關配置
  方式一:修改host,我們通過修改host文件,來實現對二級域名的,只能通過一個一個增加解析如:
    #host文件
    127.0.0.1 www.weiz.com
    127.0.0.1 a.weiz.com
    127.0.0.1 b.weiz.com
    127.0.0.1 c.weiz.com

  方式二:增加泛域名解析,配置DNS服務,也就是讓你的域名支持泛解析 (Windows Server 才會有,其他的Windows系統只能修改嘗試修改Host文件,便於測試) 請看我的另一篇文章《域名泛解析設置

  5. 效果

  

   需要注意:如果你的服務器上有多個站點,則主站不要綁定主機頭。其他二級域名的子系統,需要綁定主機頭。

   

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM