白话学习MVC(四)URL路由

简介:

本节来记录下有关URL路由的知识。

1、URL路由的是做什么的呢?  
简单的说:URL路由的功能就是分析请求的URL地址,也就是你在浏览器地址栏输入的地址,它将你请求的地址和我们定义的模版进行比较匹配。通俗的说,就是发来请求的地址和我原来定义的样式是否一样,如果匹配的话就继续执行,例如:将请求的部分信息和当前匹配的路由对象Route(定义的模版)封装到RouteData、确定处理请求的HttpHandler,不明白没关系,之后介绍。

2、URL路由是MVC特有的吗?
URL路由系统并不是专属于ASP.NET MVC的,而是直接建立在ASP.NET上。ASP.NET通过路由系统可以实现请求地址和物理文件的分离,因为ASP.NET处理请求的是一个一个实际存在物理文件,例如:Default.aspx.cs。而MVC中处理请求的是某个Controller下的Action。

3、URL路由在ASP.NET和ASP.NET MVC中使用是一样的吗?
不一样。在ASP.NET中,使用RouteTable.Routes.MapPageRoute(...)方法(RouteCollection类中的方法)来进行注册路由(),之后由PageRouteHandler来生成一个处理ASP.NET请求的HttpHandler对象,即:.aspx.cs文件;在MVC中,使用RouteTable.Routes.MapRout(...)方法(RouteCollectionExtensions类中的方法)来进行注册路由,之后由MvcRouteHandler来生成一个处理MVC请求的HttpHandler对象MVCHandler。
HttpHandler泛指那些实现了IHttpHandler接口的类

 当以上的这几个问题和问题的回答,你还有不明白的地方的话,没关系,接着看,看完下面的再回头看这上述的几个问题的。那时候就so easy ...

进入正文:

  注册URL路由:

在使用时,我们只需要在的Global.asax文件中注册响应的路由即可。以MVC为例,我们就来看注册一个路由。

复制代码
        public static void RegisterRoutes(RouteCollection routes)
        {
            routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
            routes.MapRoute(
                "Default", // 路由名称
                "{controller}/{action}/{id}", // 带有参数的 URL
                new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
            );
        }
复制代码

MapRoute方法有好多重载,就是为了注册路由提供各种条件。例如:默认路由、指定命名空间、指定域等。

注意:如果是ASP.NET程序则是利用RouteCollection对象的PageMapRoute方法来进行注册,在PageMapRoute方法中,将实例化一个Route对象并放入路由表中,当实例化Route对象时,其参数中会有一个RouteHandler(PageRouteHandler对象),这个对象的唯一方法GetHttpHandler方法会返回一个Page类(.aspx.cs文件)作为真正处理请求的类;而在MVC中,则是利用RouteCollection的扩展类RouteCollectionExtensions类的MapRoute方法来进行路由注册,跟ASP.NET不同的是,当在MVC中实例化Route对象的时,其参数中的RouteHandler是(MvcRouteHandler),这个对象的唯一方法GetHttpHandler方法返回的是个MVCHandler作为处理MVC请求的类。

就是这么简单,合理的安排注册之后就可以实现对URL的路由。

对于如何注册、以及如何安排路由的顺序等,这里也就不再介绍,网上已经有那么那么的多...

  对于本文来讲,了解如何使用URL路由不是目的,而分析URL路由的执行过程才是目的所在。

  分析执行过程

  接下来让我们来分析下执行流程,我们都知道所有发来的请求,都是通过HttpApplication的一系列事件来处理的。我们现在就以HttpApplication的各事件为主线,来分析URL路由的执行流程。

  当请求到达IIS后,经过IIS处理,然后到达程序并读取WebConfig文件中的HttpModule节点,对自定义的HttpModule进行注册,而URL路由系统是通过一个名为UrlRoutingModule的自定义HttpModule实现的,MVC中UrlRoutingModule是注册到HttpApplication的第7个事件PostResolveRequestCache事件中的,即:当执行HttpApplication到第7个事件的时候才执行URL路由的处理。


之后开始一次执行HttpApplication的各个事件,首先执行Global.asax文件中的Application_Start方法,即:进行路由的注册,也就将定义的URL模版添加的路由表中。接着开始执行已经注册到HttpApplication各事件中的方法,URL路由注册在第7个事件中。其他事件的执行内容请这里

HttpApplication事件列表

在UrlRoutingModule中,上述的注册的时候执行的是其Init方法,就是将OnApplicationPostResolveRequestCache方法和OnApplicationPostMapRequestHandler注册到事件中,当事件触发的时候,就会去执行对应的方法。

复制代码
public class UrlRoutingModule : IHttpModule
{
    protected virtual void Init(HttpApplication application)
    {  
application.PostResolveRequestCache += new EventHandler(this.OnApplicationPostResolveRequestCache); application.PostMapRequestHandler += new EventHandler(this.OnApplicationPostMapRequestHandler); } }
复制代码

执行OnApplicationPostResolveRequestCache
在此方法以及其内部调用的方法中所要完成的工作就是:遍历所有已经注册的所有路由(URL模版),并遍历的调用每个路由对象的GetRouteData方法,对请求的URL和路由进行匹配,如何失败,则返回null,如果匹配成功则返回一个RouteData对象(封装了当前路由信息),RouteData通过自己的一个属性RouteHandler用来获取注册路由时的RouteModule(PageRouteModule或MvcRouteModule),这个RouteHandler对象是在注册路由中实例化Route对象的时候创建的,如果是ASP.NET程序(即:用PageMapRoute方法注册路由),则是PageRouteModule,如果是MVC程序(即:用MapRoute方法注册路由),则是MvcRouteModule。当获取到RouteModule后,要执行相应的唯一方法GetHttphandler方法,最终返回实际处理请求的HttpHandler(.aspx.cs文件或者MVCHandler)。
注意:所有提到的HttpHandler泛指实现了IHttpHandler接口的类。
                 HttpModule泛指实现了IHttpModule接口的类。
RouteHandler指的实现了IRouteHandler的MvcRouteHandler类或PageRouteHandler类。

下面通过反编译来看下代码的执行:
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
{
    HttpContextBase context 
new HttpContextWrapper(((HttpApplication) sender).Context);
    
this.PostResolveRequestCache(context);
}
public virtual void PostResolveRequestCache(HttpContextBase context)
{
 //这里只列举重要的代码
 //遍历路由表中的所有路由,并遍历的调用每个路由的GetRouteData方法,并返回一个封装了当前匹配的路由信息的RouteData对象

    RouteData routeData 
this.RouteCollection.GetRouteData(context);
 //用来获取处理路由请求的RouteHandler,上面说过了如果是MVC程序则得到是MvcRouteHandler对象,否则是PageRouteHandler

IRouteHandler routeHandler = routeData.RouteHandler;
 //调用RoutHandler类的唯一方法GetHttpHandler,返回真正处理请求的HttpHandler(.aspx.cs文件或MvcHandler)
    IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
}
详细流程可以看看这里

  至此,URL路由系统的功能算是执行完了,他的作用也基本上体现完了。即:添加到HttpApplication的第7个事件中的功能也就收工了,接下来就会依次执行HttpApplicaiton的其他事件。之后就是在HttpApplication的第11-12个事件中,由URL路由系统的到HttpHandler来对请求进行处理!!!

 

路由系统已经讲述完毕,为了了解其运行,我觉着再来看看在URL路由系统中重要的类是很有必要的!!
RouteBase
Route
RouteData
RouteCollection
RouteCollectionExtensions


RouteBase是一个抽象类,其中只有两个抽象方法。

 public abstract RouteData GetRouteData(HttpContextBase httpContext);
public abstract VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);


Route 就是上述提到的定义URL模版,向路由表中注册的路由就是一个Route对象。
Route类唯一继承并实现RouteBase类,也就是要实现RouteBase中的两个抽象方法,GetRouteData(...)方法就是将请求的URL地址和当前模版匹配,如果成功的话,返回一个封装当前路由信息的RoutData对象。GetVirturlPath(...)方法是生成一个URL,暂时用不到,就不多介绍GetVirturlPath了。
成员:

复制代码
    public class Route : RouteBase
    {

        public Route(string url, IRouteHandler routeHandler);
        public Route(string url, RouteValueDictionary defaults, IRouteHandler routeHandler);
        public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler);
        public Route(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler);
        
     public RouteValueDictionary Constraints { get; set; } public RouteValueDictionary DataTokens { get; set; } public RouteValueDictionary Defaults { get; set; } public IRouteHandler RouteHandler { get; set; } public string Url { get; set; }
        public override RouteData GetRouteData(HttpContextBase httpContext);
        public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values);
        protected virtual bool ProcessConstraint(HttpContextBase httpContext, object constraint, string parameterName, RouteValueDictionary values, RouteDirection routeDirection);
    }
}
复制代码

 

RouteData 是一个封装路由信息的对象,当路由匹配成功之后,就是由RoueData对象来获取ModuleHandler(PageModuleHandler、MVCModuleHandler),再由这个ModuleHandler来获取处理请求的HttpHandler。
成员:

复制代码
public class RouteData
    {
        public RouteData();
        public RouteData(RouteBase route, IRouteHandler routeHandler);
        public RouteValueDictionary DataTokens { get; }
        public RouteBase Route { get; set; }
        public IRouteHandler RouteHandler { get; set; }
        public RouteValueDictionary Values { get; }
        public string GetRequiredString(string valueName);
    }
复制代码

RouteColleciton 为 ASP.NET 路由操作提供路由的集合,利用其PageMapRoute方法来进行路由注册。
RouteCollectionExtensions 扩展RouteCollection对象,进行ASP.NET MVC路由,MVC要利用其MapRoute方法来进行路由注册。

RouteCollection
RouteCollectionExtensions

 

 本篇只介绍了流程,暂没根据MVC的源代码分析路由系统!!

 


本文转自武沛齐博客园博客,原文链接:http://www.cnblogs.com/wupeiqi/archive/2013/05/09/3069905.html,如需转载请自行联系原作者

目录
相关文章
|
6月前
|
移动开发 前端开发 JavaScript
前端vue2、vue3去掉url路由“ # ”号——nginx配置(一)
前端vue2、vue3去掉url路由“ # ”号——nginx配置
498 0
|
3月前
|
Python
路由(URL routing)
【8月更文挑战第23天】
35 4
|
3月前
|
API 开发者 Python
"FastAPI路由大揭秘!轻松玩转URL映射,让你的Web应用路由设计既RESTful又灵活多变,秒杀传统框架的秘籍在这里!"
【8月更文挑战第31天】在Web开发中,路由是连接用户请求与后端逻辑的关键。FastAPI作为现代Python Web框架的佼佼者,以其简洁的API设计和高性能,提供了高度灵活的路由系统。本文通过开发一个博客系统的案例,详细介绍了FastAPI中路由的实现方法,包括基础路由定义、参数类型验证及路由分组与嵌套等,展示了如何轻松构建RESTful风格的URL映射,提升应用的可维护性和扩展性。
90 2
|
6月前
|
前端开发 JavaScript 应用服务中间件
前端vue2、vue3去掉url路由“ # ”号——nginx配置(二)
前端vue2、vue3去掉url路由“ # ”号——nginx配置
332 0
|
3月前
|
开发者 Java UED
大文件传输不再头疼:揭秘Struts 2如何轻松应对文件上传与下载难题!
【8月更文挑战第31天】在Web应用开发中,文件上传与下载至关重要。Struts 2作为主流Java EE框架,凭借Commons FileUpload及文件上传拦截器简化了相关操作。本文探讨Struts 2在文件传输上的优势,通过具体配置与代码示例,展示如何设置最大文件大小、使用`fileUpload`拦截器以及实现文件上传与下载功能。对于大文件传输,Struts 2不仅能够轻松应对,还支持上传进度显示,有效提升了用户体验。总体而言,Struts 2为文件传输提供了高效便捷的解决方案,助力开发者构建稳定可靠的Web应用。然而,在处理大文件时需兼顾网络带宽与服务器性能,确保传输顺畅。
60 0
|
3月前
|
API UED 开发者
Vaadin路由魔法:导航之舟,带你穿越页面迷宫!驾驭神奇URL,解锁无限可能!
【8月更文挑战第31天】Vaadin是一款现代Java Web开发框架,其路由机制结合前后端路由,确保流畅的用户体验和高效服务器资源利用。通过`@Route`注解和`Router`类,开发者可以轻松定义和管理页面路径。例如,`@Route("home")`可指定视图路径,而参数化路由如`@Route("user/:userId")`则允许URL传参。此外,Vaadin还提供了丰富的导航API和自定义路由事件监听器,助力开发者构建结构清晰且体验优秀的Web应用。
45 0
|
6月前
【超实用】Angular如何修改当前页面网页浏览器url后面?param1=xxx&param2=xxx参数(多用于通过浏览器地址参数保存用户当前操作状态的需求),实现监听url路由切换、状态变化。
【超实用】Angular如何修改当前页面网页浏览器url后面?param1=xxx&param2=xxx参数(多用于通过浏览器地址参数保存用户当前操作状态的需求),实现监听url路由切换、状态变化。
【超实用】Angular如何修改当前页面网页浏览器url后面?param1=xxx&param2=xxx参数(多用于通过浏览器地址参数保存用户当前操作状态的需求),实现监听url路由切换、状态变化。
|
6月前
|
开发框架 搜索推荐 中间件
中间件应用路由和URL重写
【5月更文挑战第2天】中间件应用路由和URL重写
51 3
中间件应用路由和URL重写
|
5月前
|
安全 前端开发 测试技术
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
安全开发-PHP应用&模版引用&Smarty渲染&MVC模型&数据联动&RCE安全&TP框架&路由访问&对象操作&内置过滤绕过&核心漏洞
|
6月前
【超实用】Angular如何修改当前页面网页浏览器url后面?param1=xxx&param2=xxx参数(多用于通过浏览器地址参数保存用户当前操作状态的需求),实现监听url路由切换、状态变化。
【超实用】Angular如何修改当前页面网页浏览器url后面?param1=xxx&param2=xxx参数(多用于通过浏览器地址参数保存用户当前操作状态的需求),实现监听url路由切换、状态变化。