以路由控制URL
至此为止,我们一直在使用ASP.NET MVC新项目随带的默认路由配置。现在我们将深入探讨路由系统,并学习如何创建应用程序的自定义路由,以确保URL既是用户友好又是搜索引擎可访问的。
路由的全部内容都是关于URL以及如何将URL作为应用程序的外部输入的。当使用其他开发工具,如PHP、Web Form或是经典的ASP时,URL通常对应于磁盘上的物理文件。一个http://example.com/Products.aspx这样的URL会导致执行负责处理该请求的名为Products.aspx的文件。
通过使用URL路由,ASP.NET MVC解除了URL与物理文件的耦合。路由提供了一种把无扩展名的URL映射到控制器动作的方式,让开发人员对URL方案有完全的控制。
在本章中,我们将介绍路由概念及其与MVC应用程序的关系,还将简要介绍它们如何用于ASP.NET Web Form项目。我们将考察如何设计应用程序的URL方案,然后将这些概念运用于创建一个示例应用程序的路由。最后看看如何测试路由,以确保它们按预期工作。
一、介绍URL路由
与将URL绑定到磁盘上的物理文件不同,ASP.NET MVC引入的URL路由的底层结构能够将URL映射到控制器动作,而无须在服务器上有物理文件作为URL的目标。在本节中,我们将考察新建MVC项目随带的默认路由的结构,以及这些路由是如何与控制器和动作的概念相关联的。
1.默认路由
当创建一个新的ASP.NET MVC应用程序时,默认的项目模板会在Global.asax文件中调用一个名称为RegisterRoutes的方法。该方法负责为应用程序配置路由,并定义了最初两条路由——一条忽略路由和一条遵循{controller}/{action}/{id}模式的默认路由,如下所示。
路由是通过调用MapRoute方法而定义的,该方法有个过载。在这个例子中,默认路由是通过调用三个参数的过载来配置的。第一个参数是路由名("Default")。第二个参数是用来匹配URL的URL模式。本例中,URL模式被定义为具有三个片段——控制器、动作和ID。第三个参数是一个匿名类型,它为这些片段定义了默认值。
如果用户访问http://example.com/users/edit/5这样的URL,这将匹配默认路由,因为它有三个片段,如图所示。
在这个例子中,字符串users映射到controller参数,edit映射到actio,而5映射到id。由于这个URL显然与路由相匹配,MVC框架会尝试查找名称为UsersController的类、调用Edit方法,并为其id参数传递5。如果找不到控制器或动作,框架会产生一个404错误。
添加到路由定义中的默认参数意味着URL不必精确地匹配三片段URL模式。如果指定了默认控制器Home以及默认动作Index,当控制器片段省略时,路由将默认控制器为HomeController。同样,如果动作片段未指定,则路由会默认寻找Index动作。Id参数的默认值UrlParameter.Optional,意指不论是否指定第三个片段,路由都可以被匹配。下表给出了几个能匹配默认路由的例子。
URL | 路由参数 | 被选中的动作方法 |
http://example.com/Users/Edit/5 | Controller=User, Action=Edit, id=5 | UsersController.Edit(5) |
http://example.com/Users/Edit | Controller=User, Action=Edit | UsersController.Edit() |
http://example.com/Users | Controller=User, Action=Index | UsersController.Index() |
http://example.com | Controller=User, Action=Index | HomeController.Index() |
在IgnoreRoute方法中,模式{resource}.axd/{*pathInfo}确保文件扩展名为.axd的任何URL不会被路由引擎所处理,这样才能确保任何自定义HTTP处理程序(其扩展名为.axd)以正确方式呗处理,而不会被路由引擎拦截。
2.入站与出站路由
入站路由(Inbound Routing):将URL映射到控制器或动作及任何附加参数。
出站路由(Outbound Routing):通过一组给定的路由数据(通常是控制器和动作)生成相应的URL。
上图所示的入站路由描述了一个控制器动作的URL调用。HTTP请求进入ASP.NET管道,并通过ASP.NET MVC应用程序注册的路由进行发送。每个路由都有处理请求的机会,而匹配路由随后会指定被使用的控制器和动作。
二、设计URL模式(schema)
1.建立简单、整洁的URL
传统URL:http://example.com/eventmanagement/events_by_month.aspx?year=2011&month=4
使用路由系统的URL:http://example.com/events/2011/04
这种URL带来的好处是,其中的日期有了一种明确的层次格式。
2.建立可破解的URL
在设计URL方案时,考虑最终用户为了改变所显示的数据要如何操纵或“破解”URL是有价值的。例如,也许可以合理地假设,从以下URL移去参数“04”,可能表示2011年发生的全部事件:
http://example.com/events/2011/04
同样的逻辑可以形成下表所示的更全面的路由列表。
URL | 描述 |
http://example.com/events | 显示全部事件 |
http://example.com/events/<year> | 显示某年事件 |
http://example.com/events/<year>/<month> | 显示某月事件 |
http://example.com/events/<year>/<month>/<day> | 显示某日事件 |
让URL模式具有这种灵活性是很棒的,但这可能会导致应用程序中具有大量潜在的URL。在建立应用程序视图时,你总是要改出相应的导航。记住,可能在各个页面上不必对每个可能的URL组合都包含一个链接。在用户试图破解URL并使其生效时,让用户有一些惊喜的发现反而是件好事。
如果不希望用户破解,可考虑使用连接字符来替代斜线,如/events/2008-04-01。
3.使用URL参数区分请求
让我们对此路由加以扩展,并允许按类别列出事件。从用户的观点来看,最有用的URL可能像这样:
http://example.com/events/aspnet-usergroup-meeting
但现在有问题了!我们已经有了一个与/events/<something>形式匹配的路由,用来列出特定年、月、日的事件,那么现在如何用/events/<something>也匹配类别?第二个路由片段现在意味着完全不同的含义,这与现有的路由不协调了。如果把这种URL交给路由系统,它应该把这种参数可能作类别还是日期?
幸运的是,ASP.NET MVC的路由系统允许我们运用条件,使用正则表达式来确保路由只与某个模式的参数相匹配就够了。这意味着我们可以只用一条路由,就能让/events/2011-01-01形式的请求传递给按日期显示事件的动作,而让/events/asp-net-mvc-in-action形式的请求传递给按类别显示事件的动作。
4.尽可能避免暴露数据库ID
一个用于托管开发人员事件的网站可能会定义这样的URL:
http://example.com/events/87
87是从数据库获得的每一个对象都有一个主键形式的唯一标识符,但是除了数据库管理员之外,数字87对任何人都毫无意义。因此,应该尽可能避免在URL中使用数据库生成的ID,尽量让它们有意义、可读、易于理解。
http://example.com/events/houstonTechFest2010
5.考虑添加多余信息
如果必须在URL中使用数据库ID,可考虑添加除了使URL可读外没什么目的的附加信息。
http://example.com/events/houstonTechFest2010/session-87
http://example.com/events/houstonTechFest2010/session-87/an-introduction-to-mvc
--------------------------------------------------------------------
搜索引擎优化(SEO)
当涉及网站的搜索引擎优化方面时,有必要提一提设计良好的URL的价值,在URL中放置一个相关的关键字提升搜索引擎排序。设计要点如下:
- 为控制器和动作使用描述性的、简单的、普遍使用的单词。力求尽可能相关并使用可能用于所建页面的关键词。
- 当在路由中包含文本参数时,用连接字符替换所有的空格符。
- 去掉字符串参数中不重要的标点和不必要的文本。
- 在URL可能的地方包含附加的、有意义的信息,如标题和描述等。
----------------------------------------------------------------------
三、在ASP.NET MVC中实现路由
默认项目模板创建了两个默认路由,但你可以不接受这两个默认路由的限制,添加自己的路由,以实现完全自定义的URL模式。以下将对此加以演示,以一个简单的在线商店为例,实现几个路由。我们将考察如何创建简单、静态的路由,以及创建更复杂的使用参数的路由和全匹配路由。
1.在线商店的URL模式(重要)
路由号 | URL | 描述 |
1 | http://example.com/ | 首页,重定向到分类列表 |
2 | http://example.com/privacy | 显示包含网站私有策略的静态页面 |
3 | http://example.com/products/<productcode> | 显示相应产品代码的产品详情页面 |
4 | http://example.com/products/<productcode>/buy | 将相应产品添加到购物篮 |
5 | http://example.com/basket | 显示当前用户的购物篮 |
6 | http://example.com/checkout | 启动当前用户的结算过程 |
注意:路由4中的URL不是设计给用户看的,它通过表单递交进行链接,在动作处理完成后会立即进行重定向,因而这种URL不会在地址栏中出现。
2.添加自定义静态路由
路由1是由默认路由处理的。
路由2,是一个纯静态路由,将http://example.com/privacy映射到HomeController的Privacy动作。
routes.MapRoute("privacy_policcy","privacy", new { controller="Home", action="Privacy"});
警告:添加到路由表中的路由次序决定了查找匹配时的路由搜索顺序。这意味着,源代码中列出的路由,应当从带有最具体条件的最高优先级降低到最低优先级,或全匹配路由。
3.添加自定义的动态路由
当有少量偏离一般规则的URL时,静态路由是有用的。如果路由包含与页面显示的数据相关的信息,就需要动态路由了。
路由3和路由4是用两个路由参数实现的:
routes.MapRoute("Product", "products/{productCode}/{action}", new { controller="Catalog", action="Show"});
两个占位符将匹配URL中用斜线分隔的片段,productCode参数是必需的,但action是可选的。如果action未指定,该路由会默认指向CatalogController上的Show动作,并传递productCode参数。详细代码如下。
public class CatalogController : Controller
{
private ProductRepository _productRepository = new ProductRepository(); public ActionResult Show(string productCode)
{
var product = _productRepository.GetByCode(productCode); if (product == null)
{
return new NotFoundResult();
}
return View(product);
} }
实现一个执行时能生成HTTP 404的自定义动作结果:
public class NotFoundResult:ActionResult
{
public override void ExecuteResult(ControllerContext context)
{
context.HttpContext.Response.StatusCode = ;
new ViewResult { ViewName = "NotFound" }.ExecuteResult(context);
}
}
}
NotFoundResult通过集成ActionResult,在其中提供了必须实现的ExecuteResult方法。该方法将响应状态码设置为404,然后渲染一个名为NotFound的视图,该视图位于Views/Shared目录。
注意:HttpNotFoundResult动作,也将响应转台码设置为404,但它未提供显示自定义错误页面的机制,因此总是会给最终用户显现一个空屏。
最后,我们可以添加模式中的路由5和路由6。
routes.MapRoute{"catalog", "{action}",
new { controller="Catalog" },
new { action=@"basket|checkout"});
这些路由几乎是静态路由,只不过它们是用一个参数和一个路由约束来实现的,以保持较少的路由数目。这么做的主要原因有两个。第一,每个请求都必须扫描路表进行匹配,所以大的路由集合会影响到性能。第二,路由越多,路由优先级问题出现的风险也越高。较少数目的路由规则更易于维护。
MapRoute方法的第四个参数包含了路由约束。约束参数是一个匿名类型形式的字典,可以用于指定如何约束特定的路由参数。在本例中,我们使用了一个正则表达式来指明,仅当片段字符串为“basket”或“checkout”时,才匹配action参数。这种约束能够适当地阻止把未知动作传递给控制器。
4.全匹路由
我们现在已经添加了静态和动态路由,以便为网站的不同URL提供内容。但假设有一个与所有路由都不匹配的请求,会发生什么?结果会抛出一个异常,这是实际应用程序中不希望发生的事情。为了对此加以处理,我们可以使用与ASP.NET的错误处理基础架构结合在一起的全匹配路由。
我们将添加一个全匹配路由,用它匹配尚未被其他路由匹配的任何URL,显示HTTP404的错误消息,它应该是最后一条被定义的路由。
routes.MapRoute("404-catch-all", "{*catchall}",
new { controller="Error", action="NotFound"});
值catchall为全匹配路由要拾取的值提供了一个名称。与规则路由参数不同,全匹配参数(以星号为前缀)会捕获包括正斜线在内的整个URL部分,正斜线通常用于分隔路由参数。在上述示例中,该路由被映射到ErrorController的NotFound动作。
public class ErrorController: Controller
{
public ActionResult NotFound()
{
return new NotFoundResult();
}
}
现在,可以删去默认的{controller}/{action}/{id}路由,因为我们已经完全定制了路由,以匹配我们的URL模式。或者,你也许会选择保留它,以作为访问其他控制器的一种默认方式。
四、使用路由系统生成URL
每当网站中需要一个URL时,我们都要求框架给出,而不是采用硬编码。我们需要制定一种控制器、动作以及参数的组合,剩下的由ActionLink方法完成。ActionLink是MVC框架中HtmlHelper类上的一个扩展方法,它会生成一个插入了正确URL的完整的HTML<a>元素,该URL与传递进来的对象参数所指定的路由相匹配。以下是调用ActionLink的一个例子:
@Html.ActionLink ( "MVC3 in Action", "Show", "Catalog",
new { productCode = "mvc-in-action" }, null )
第一个是超链接的显示文本;第二个和第三个指定了要被链接到的动作和控制器;第四个采用了一个匿名类型形式的字典,以指定任意的附加路由参数;最后一个是仍以匿名类型形式指定的任意的附加HTML属性。
使用前面定义的路由,这个例子会生成一个链接,指向CatalogController上的Show动作,并带有为productCode指定的附加参数。以下是其输出:
<a href="/products/mvc-in-action">MVC3 in Action</a>
类似地,如果使用HtmlHelper的BeginForm方法来建立表单标签,它会为你生成URL。有时,能够将路由部分未指定的参数传递给动作时有用的:
@Html.ActionLink ( "MVC3 in Action", "Show", "Catalog",
new { productCode = "mvc-in-action", currency="USD" }, null )
如果该参数与路由中的某个部分匹配,它将成为URL的一部分。否则,它将被附加到查询字符串。比如,以下是上述代码生成的链接:
<a href="/products/mvc-in-action?currency=USD">MVC3 in Action</a>
在使用ActionLink时,被选中的路由是路由集合中所定义的第一个匹配路由。大多数情况下,这是足够的,但如果你希望请求一条特定的路由,可以使用RouteLink,它接受一个标识被请求路由的参数,像这样:
@Html.RouteLink ( "MVC3 in Action", "Show", "Catalog",
new { productCode = "mvc-in-action" }, null )
这个代码将查找一个带有product名称的路由,而不是指定的控制器和动作。
有时候你需要获得一个URL,但不是为了链接或表单。这通常发生在编写Ajax代码需要设置一个请求URL时。UrlHelper类能够直接生成URL,由ActionLink方法和其他方法所使用。以下是一个例子:
@Url.Action ( "Show", "Catalog",
new { productCode = "mvc-in-action" } )
这个代码也返回/products/mvc-in-action,但没有任何包围标签。
以路由控制URL的更多相关文章
- python 全栈开发,Day68(Django的路由控制)
昨日内容回顾 1 MVC和MTV MTV 路由控制层(分发哪一个路径由哪一个视图函数处理) V : views (逻辑处理) T : templates (存放html文件) M : model (与 ...
- 5 解析器、url路由控制、分页、渲染器和版本
1 数据解析器 1 什么是解析器 相当于request 中content-type 对方传什么类型的数据,我接受什么样的数据:怎样解析 无论前面传的是什么数据,都可以解开 例如:django不能解析j ...
- angularJs模块ui-router之路由控制
在你的应用中大多数状态都有与其相关联的 url,路由控制不是设计完成 state 之后的事后想法,而是开始开发时就应该考虑的问题. 这里是如何设置一个基本url. $stateProvider .st ...
- Router和History (路由控制)-backbone
Router和History (路由控制) Backbone.Router担任了一部分Controller(控制器)的工作,它一般运行在单页应用中,能将特定的URL或锚点规则绑定到一个指定的方法(后文 ...
- golang自定义路由控制实现(二)-流式注册接口以及支持RESTFUL
先简单回顾一下在上一篇的文章中,上一篇我主要是结合了数组和Map完成路由映射,数组的大小为8,下标为0的代表Get方法,以此类推,而数组的值则是Map,键为URL,值则是我们编写对应的接口.但 ...
- rest_framework之解析器、路由控制、分页
解析器 我们都知道,网络传输数据只能传输字符串格式的,如果是列表.字典等数据类型,需要转换之后才能使用 但是我们之前的rest_framework例子都没有转换就直接可以使用了,这是因为rest_fr ...
- Django-restframework之路由控制、解析器及响应器
django-restframework之路由控制.解析器及响应器 一 前言 本篇博客介绍 restframework 框架的剩下几个组件,路由控制有三种:传统路由.半自动路由及全自动路由:解析器是用 ...
- web应用/路由控制/视图函数/单表多表操作
一. 1.wen应用:BS架构的应用程序,B是浏览器,S:server(实现了wsgi协议)+ application https://www.cnblogs.com/liuqingzheng/art ...
- $Django patch与put,视图组件,路由控制,响应器
1 patch与put(幂等?回顾) PATCH 与 PUT 属性上的一个重要区别还在于:PUT 是幂等的,而 PATCH 不是幂等的.幂等是一个数学和计算机学概念,在计算机范畴内表示一个操作执行任意 ...
随机推荐
- 在systemd(CentOS7)自启动zookeeper
zookeeper的自启动脚本,如果是 sysV 模式(CeontOS6或以下版本),可以直接使用下载版本中的 src 目录下对应的 sysV 自启动包,再chkconfig即可.老方法,简单,就不说 ...
- haproxy 超时机制
<pre name="code" class="python">option redispatch option redispatch 是否允许重新 ...
- 禁止apache显示目录索引
1)修改目录配置: 复制代码 代码如下: <Directory "D:/Apache/blog.phpha.com">Options Indexes FollowSym ...
- [置顶] JDK-Future 模式和实现
最近的项目用到了多线程,发现java.util.concurrent.Future蛮好用的. 像平时,写多线程一般使用Thread/Runnable,直接扔给线程池执行就好了.但是遇到了一些需要获取线 ...
- PHP移动互联网开发(1)——环境搭建及配置
原文地址:http://www.php100.com/html/php/rumen/2014/0326/6702.html 一.PHP5.4环境搭配基本流程 Apache:Web服务提供者.官网:ww ...
- Cocos2d-x 3.0 使用TinyXml 解析XML文件
在cocos2d-x 3.0中Xml解析已经不用自己找库了,已经为我们集成好了. text.xml <!--?xml version ="1.0" encoding =&qu ...
- Webstorm入门-----常用快捷键
为了提高敲代码的速度.我们所需要关注的各种快捷键: 首先,快捷键的设置 相关连接: http://www.cnblogs.com/dc10101/archive/20 ...
- ppt类似工具AxeFile使用心得
一个所谓的傻瓜式过渡效果自动生成工具.定义好展示窗口大小,加入时序.所谓的闪烁效果,也是相当的滑稽. 是一个非专业的简单的快速PPT工具. 但是体现的确是扁平化的设计思路,很值得深思. ------ ...
- JavaBean的一个小例子
一.创建一个javaBean类: UseBean package com.oncall24h.ruchi; import java.io.Serializable; public class UseB ...
- swift + xcode 新手上路
有用的参考博文: 视频教程: 如何创建第一个iPhone App - HelloWorldHelloWorld 熟悉xcode: http://www.cocoachina.com/swift/201 ...