前段时间,一个朋友问我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(":") > )
      {
        requestDomain = requestDomain.Substring(, requestDomain.IndexOf(":"));
      }
    }
    else
    {
      requestDomain = httpContext.Request.Url.Host;
    }
    string requestPath = httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring() + 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 = ; 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, ))
          {
            if (!string.IsNullOrEmpty(group.Value))
            {
              data.Values[key] = group.Value;
            }
          }
        }
      }       // 匹配域名路径
      for (int i = ; 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, ))
          {
            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 = ; 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. 效果

  

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

   

MVC实现动态二级域名的更多相关文章

  1. MVC动态二级域名解析

    动态二级域名的实现: 应用场景:目前产品要实现block功能,因为工作需要实现二级域名:www.{CompanyUrl}.xxx.com 假设产品主域名入口为:www.xxx.com 公司员工管理:w ...

  2. MVC利用Routing实现多域名绑定一个站点、二级域名以及二级域名注册Area

    最近有这么个需求:在一个站点上绑定多个域名,每个域名进去后都要进入不同的页面.实现了这个功能以后,对于有多个域名,且有虚拟空间,但是虚拟空间却只匹配有一个站点的用户来说,可以节省很多小钱钱. 很久以前 ...

  3. asp.net MVC把Areas区域绑定成二级域名

    先分析需求 在MVC项目中,我们如果有两个Areas.比如Test和DEMO.我们的访问地址应该是 http://localhost:8098/test http://localhost:8098/d ...

  4. asp.net core mvc中如何把二级域名绑定到特定的控制器上

    由于公司的工作安排,一直在研究其他技术,所以一直没时间更新博客,今天终于可以停下手头的事情,写一些新内容了. 应用场景:企业门户网站会根据内容不同,设置不同的板块,如新浪有体育,娱乐频道,等等.有的情 ...

  5. mvc 二级域名 重定向

    使用mvc开发了一个独立的站点(wechat),但是最后要和并到另外一个站点下(admin),但是外部访问要使用另一个站点(admin)的二级域名 考虑之后采用mvc路由机制来实现(这也要考虑),代码 ...

  6. 动态DNS——本质上是IP变化,将任意变换的IP地址绑定给一个固定的二级域名。不管这个线路的IP地址怎样变化,因特网用户还是可以使用这个固定的域名 这样看的话,p2p可以用哇

    动态域名是因应网络远程访问的需要而产生的一项应用技术.因为没有固定IP,只能运用二级域名来应对经常变化的IP,动态域名的由来因此而产生. 它当前主要应用在:路由器.网络摄像机.带网络监控的硬盘录像机. ...

  7. ASP.NET MVC3.0或4.0设置二级域名的方法

    之前我就想做二级域名指向同一个IP同一个程序无非是在路由匹配规则上做文章也就是对Url的重写的一种思路.我用了半天时间上网查阅了相关资料并做了Demo测试是完全 以的,在这分享给大家... 假如网站主 ...

  8. Nginx中rewrite实现二级域名、三级域名、泛域名、路径的重写

    最常见的: 静态地址重定向到带参数的动态地址 rewrite "^(.*)/service/(.*)\.html$" $1/service.php?sid=$2 permanent ...

  9. 织梦dedecms移动版设置二级域名的方法 织梦如何设置m.开头的域名

    dedecms/' target='_blank'>织梦dedecms建站系统自从2015.06.18号升级后,系统增加了最强的手机站功能,模板与PC模板分开,标签90%类似,数据同步,很牛很强 ...

随机推荐

  1. 问题-栈S最多能容纳4个元素,现有6个元素按A、B、C、D、E、F顺序进栈,问可能的出栈顺序。

    住栈的特性:对于取出栈内元素每次只能从栈顶开始取(后进先出(栈满时,只能先出后进)) 由于栈内只能容纳4个元素: 所以 E F不可能第一个出栈: 当栈内少于四个元素时 既可以选择进栈,也可以选择出栈 ...

  2. linux-查看系统是32位还是64位

    可以用命令“getconf LONG_BIT”查看, 如果返回的结果是32则说明是32位,返回的结果是64则说明是64位. 此外还可以使用命令“uname -a”查看, 输出的结果中,如果有x86_6 ...

  3. html-div自动撑大

    下面提供几种解决方案,以修复该问题. 1.给父容器使用display属性 div#container { display: table; /* 建议使用 */ /*或者 display: table- ...

  4. SpringMVC与Struts2区别与比较总结

    1.Struts2是类级别的拦截, 一个类对应一个request上下文,SpringMVC是方法级别的拦截,一个方法对应一个request上下文,而方法同时又跟一个url对应,所以说从架构本身上Spr ...

  5. Leetcode 200. number of Islands

    Given a 2d grid map of '1's (land) and '0's (water), count the number of islands. An island is surro ...

  6. O(nlogn)LIS及LCS算法

    morestep学长出题,考验我们,第二题裸题但是数据范围令人无奈,考试失利之后,刻意去学习了下优化的算法 一.O(nlogn)的LIS(最长上升子序列) 设当前已经求出的最长上升子序列长度为len. ...

  7. win10 1607 密匙

    win10 1607 安装密钥 GVLK Core=YTMG3-N6DKC-DKB77-7M9GH-8HVX7 Professional=VK7JG-NPHTM-C97JM-9MPGT-3V66T E ...

  8. css伪元素研究(::before/::after)

    ::before/::after和:before/:after实质上效果一样 不过,在 CSS3 中为了区别伪元素和伪类为伪元素使用了双冒号,因此如果使用了 display 或者 width 等属性时 ...

  9. Win10中解决SYSTEM权限获取,删Windows old

    一.[Windows.old]文件夹[右键]->[属性] 二.[安全]->[高级] 三.[更改] 四.添加[Everyone],点击[确定] 五.如下图,勾选两个选项,再[确定] 六.一路 ...

  10. Linux inode && Fast Directory Travel Method(undone)

    目录 . Linux inode简介 . Fast Directory Travel Method 1. Linux inode简介 0x1: 磁盘分割原理 字节 -> 扇区(sector)(每 ...