zoukankan      html  css  js  c++  java
  • 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. 效果

      

       需要注意:如果你的服务器上有多个站点,则主站不要绑定主机头。其他二级域名的子系统,需要绑定主机头。

       

  • 相关阅读:
    BZOJ 3282: Tree( LCT )
    BZOJ 3713: [PA2014]Iloczyn( 枚举 )
    HDU3974
    CodeForces220B
    POJ2349
    HDU3038
    POJ1611
    IELTS
    POJ1125
    POJ2109
  • 原文地址:https://www.cnblogs.com/zhangweizhong/p/4801486.html
Copyright © 2011-2022 走看看