前段时间,一个朋友问我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. localStorage和sessionStorage

    首先自然是检测浏览器是否支持本地存储. 在HTML5中,本地存储是一个window的属性,包括localStorage和sessionStorage,从名字应该可以很清楚的辨认二者的区别,前者是一直存 ...

  2. js-字符串转化日期

    endLogTimeDate = “2012-05-22 17:10:46” startLogTimeDate = “2012-05-22 17:10:46” var endLogTimeDate = ...

  3. iframe与主框架跨域相互访问方法【转】

    转自:http://blog.csdn.net/fdipzone/article/details/17619673 1.同域相互访问 假设A.html 与 b.html domain都是localho ...

  4. js-关于性能优化的一些学习总结

    性能优化的方法有: 1.减少HTTP请求:合并CSS/JS,使用CSS sprite等 2.压缩CSS/JS/图片 3.样式表放头部,JS放body底部:JS放在head中,将会等到js全部下载解析和 ...

  5. jquery插件-表单验证插件-提示信息中文化与定制提示信息

    接上一篇 2)messages 提示:修改默认的提示信息最简单的方法是引入message_zh.js文件即可! 如果需要在validate()方法内提示则可以使用本选项 类型:Object 说明:自定 ...

  6. 【bzoj1018】 SHOI2008—堵塞的交通traffic

    http://www.lydsy.com/JudgeOnline/problem.php?id=1018 (题目链接) 题意 一个2行C列的矩形网格,网格上的每个点代表一个城市,相邻的城市之间有一条道 ...

  7. [Noi2016十连测第五场]二进制的世界

    #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #i ...

  8. C# 调用api的方法

    问题场景: ASP.NET MVC Web API 定义 Post 方法,HttpClient 使用 JsonConvert.SerializeObject 传参进行调用,比如 Web Api 中定义 ...

  9. BZOJ2426 [HAOI2010]工厂选址

    Description 某地区有m座煤矿,其中第i号矿每年产量为ai吨,现有火力发电厂一个,每年需用煤b吨,每年运行的固定费用(包括折旧费,不包括煤的运费)为h元,每吨原煤从第i号矿运到原有发电厂的运 ...

  10. Jenkins项目构建结果通知Email的替代方案Wall Display插件

    插件:https://wiki.jenkins-ci.org/display/JENKINS/Wall+Display+Plugin 效果: 操作: 直接在一个大屏幕上打开这个项目的构建页面,那么每次 ...