前段时间,一个朋友问我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. idea 新建web项目

  2. 微信扫码支付 php

    仔细看了一遍官方的那幅流程图,我来简化理解一下(注意:我这里针对的是扫码支付模式一,模式二没什么说的)网站后台生成二维码,当然是跟据前台传来的参数有条件的生成买家扫描二维码,扫描过程中,微信后台系统回 ...

  3. mysql-删除日志文件命令详解

    装载 在mysql中会生大量的如mysq-bin.000001这类日志文件了,这些都是二进制文件了,如果我们是普通的日志没有进行主从配置就可以直接使用reset master进行删除了这个方法很简单, ...

  4. WordPress 博客文章时间格式the_time()设置

    国外设计的WordPress 主题里的文章的时间格式是类似“十一月 21, 2010”这种格式的,而中国人习惯的是年在前,月紧跟其后,日在末尾,所以看国外的就显得很别扭,但是我们可以通过修改WP时间代 ...

  5. css 去除 a,checkbox 框 出现虚线

    在开发过程中遇到checkbox框,第一次遇到还以为是系统自带的是这样 后来发现不是那样, 我们可以在使用css 去掉出现的虚线框,以下是我的解决方案代码: /* checkbox 去掉虚框*/:fo ...

  6. 测试人员如何搭建Selenium-Grid2环境(参考Java)

    Selenium对于我们进行web自动化测试有很大的帮助,如果要进行大范围的测试覆盖,就不能仅仅在一两台机器上跑了:同样Selenium-Grid也给我们提供了这样的帮助,我们可以借助Selenium ...

  7. 【caffe】mnist训练日志

    @tags caffe 前面根据train_lenet.sh改写了train_lenet.py后,在根目录下执行它,得到一系列输出,内容如下: I1013 10:05:16.721294 1684 c ...

  8. 【bzoj1499】 NOI2005—瑰丽华尔兹

    http://www.lydsy.com/JudgeOnline/problem.php?id=1499 (题目链接) 题意 给出一个n*m的地图,刚开始人在(x,y),每次给出一段区间(l,r,t) ...

  9. codeforces 342E :Xenia and Tree

    Description Xenia the programmer has a tree consisting of n nodes. We will consider the tree nodes i ...

  10. Android成长日记-使用ToggleButton实现灯的开关

    案例演示 此案例实现思路:通过ToggleButton控件,ImageView控件实现 ---xml代码: <!-- textOn:true textOff:falase[s1] --> ...