65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 ASP.NET 路由解决 404 错误

starIconstarIconstarIconstarIconstarIcon

5.00/5 (10投票s)

2008年12月28日

CPOL

4分钟阅读

viewsIcon

50134

downloadIcon

406

使用 ASP.NET 路由避免 404 Not Found 错误。

引言

本文介绍了一种使用 ASP.NET 路由来避免在更改网站的文件夹结构或文件夹名称时出现 404 Not Found 错误的方法。

如何处理网站上的失效链接?

拥有一个网站意味着需要花费一些时间和精力在互联网上推广该网站,确保搜索引擎索引所有页面,并通过博客或讨论板来获得曝光。

然后,您有了新的想法,并且确实需要重构您的网站 - 更改一些文件夹名称,移动一些页面等等。您当初引以为豪的网站上的所有第三方链接将会怎样?您想失去它们吗?

将旧 URL 路由到新的网站结构

随着 .NET Framework 3.5 SP1 的发布,我们有了一个优雅的解决方案 - ASP.NET 路由。最初,它是 ASP.NET MVC Preview 2 的一部分,现在它已成为框架的一部分。

其思想是向网站添加特殊的“路由”,其唯一目标是处理对网站上已不存在的页面的请求。最简单的形式是,处理可以在单个 ASPX 页面中完成,该页面负责正确处理请求。示例如下

附带的项目包含了您需要的所有部分:由Chris Cavanagh创建的WebFormRouteHandler,它实现了IRouteHandler接口;一个注册您的路由的Global.asax文件;一个注册WebFormRouteHandlerweb.config文件;以及一个负责实际请求处理的Default.aspx页面。

我们来看一下Global.asax文件

void Application_Start(object sender, EventArgs e)
{
    // runs on application startup
    RegisterMyRoutes(System.Web.Routing.RouteTable.Routes);
}

private void RegisterMyRoutes(System.Web.Routing.RouteCollection routes)
{
    // reference IRouteHandler implementation
    // (example created by Chris Cavanagh)
    // see http://chriscavanagh.wordpress.com/
    //            2008/03/11/aspnet-routing-goodbye-url-rewriting/
    var startPageRouteHandler = new WebFormRouteHandler("~/default.aspx");

    // exclude .axd to handle web services and AJAX without checking all routs
    // see http://msdn.microsoft.com/en-us/library/
    //            system.web.routing.stoproutinghandler.aspx
    routes.Add(new System.Web.Routing.Route("{resource}.axd/{*pathInfo}", 
               new System.Web.Routing.StopRoutingHandler()));
    routes.Add(new System.Web.Routing.Route("{service}.asmx/{*path}", 
               new System.Web.Routing.StopRoutingHandler()));

    // mapping:
    // extracts folder name and page name as items in HttpContext.Items
    routes.Add(new System.Web.Routing.Route("{folderName}/", 
               startPageRouteHandler));
    routes.Add(new System.Web.Routing.Route("{folderName}/{pageName}", 
               startPageRouteHandler));
}

在这里,我们定义了一个路由处理程序 - default.aspx,以及路由规则。

规则 #1

routes.Add(new System.Web.Routing.Route("{folderName}/", startPageRouteHandler));

指出,如果网站上不存在名为“something”的实际文件,则所有结构为“http://mysite.com/something”的 URL 请求都将由default.aspx页面处理。例如,网站上存在一个RealPage.aspx页面,那么对http://mysite.com/RealPage.aspx的请求将由该页面处理。

但是,如果客户端请求RealPage2.aspx,则根据规则 #1,该请求将由default.aspx页面处理。请注意,客户端不会被重定向到default.aspx,而只是 Web 服务器在响应请求时运行default.aspx中的代码。对于客户端而言,响应将来自RealPage2.aspx

您可以添加任意数量的路由,例如,规则 #2

routes.Add(new System.Web.Routing.Route("{folderName}/{pageName}", startPageRouteHandler));

指出,如果网站上不存在名为“somefolder/somethingelse”的实际文件,则所有结构为“http://mysite.com/somefolder/somethingelse”的 URL 请求都将由default.aspx页面处理。

default.aspx的代码隐藏文件显示了如何提取请求的这些部分。如您所见,它们将被放置在HttpContext.Items集合中。

lblFolder.Text = Context.Items["folderName"] as string;
lblPage.Text = Context.Items["pageName"] as string;

在实际生活中如何工作

这是一个正在实际使用此技术的真实网站 - Digitsy Global Store。除了处理失效 URL 外,ASP.NET 路由还用于处理网站上的多语言,动态切换CultureInfo

protected void Page_PreInit(object sender, EventArgs e)
{
    CultureInfo lang = new CultureInfo(getCurrentLanguage());
    Thread.CurrentThread.CurrentCulture = lang;
    Thread.CurrentThread.CurrentUICulture = lang;
}
private static string getCurrentLanguage()
{
    string lang = HttpContext.Current.Items["language"] as string;
    switch (lang)
    {
        case "france":
            return "fr-FR";
        case "canada":
            return "en-CA";
        case "germany":
            return "de-DE";
        case "japan":
            return "ja-JP";
        case "uk":
            return "en-GB";
        case "russia":
            return "ru-RU";
        default:
            return "en-US";
    }
}

如您所见,默认语言是美国英语:“en-US”。在内部链接中,网站使用结构http://{sitename}/{language}/…其他内容…

因此,如果您尝试访问http://digitsy.com/us/,您将获得美国版本;尝试访问http://digitsy.com/japan/将为您带来日本版本;如果您尝试访问http://digitsy.com/whatever - 您不会收到 404 错误,您将再次获得美国版本。

ASP.NET 路由使网站重构变得非常容易。文件夹结构“{language}/{index}/category/{categoryID}”最近被替换为“{language}/{index}/shopping/{categoryID}”。网站结构中不应再有“category”文件夹。但是,由于两个路由都指向同一个处理页面,因此“category”和“shopping”这两个文件夹都返回有效响应。

尝试访问http://digitsy.com/us/Electronics/shopping/541966将使用规则

routes.Add(new System.Web.Routing.Route("{language}/{index}/shopping/{categoryID}", 
           categoryRouteHandler));

而尝试访问http://digitsy.com/us/Electronics/category/541966将使用

routes.Add(new System.Web.Routing.Route("{language}/{index}/category/{categoryID}", 
          categoryRouteHandler));

这两个路由都将解析到同一个路由处理页面。

需要记住的事情

如果您知道自己在做什么,这真的很简单。我的意思是,您应该了解一些潜在的影响。请查看Phil Haack 的帖子,其中讨论了“在使用路由和 URL Authorization 时需要注意的一个微妙的潜在安全问题”。

您还应该验证您的托管提供商是否支持 .NET Framework 3.5 的 SP1。许多托管提供商由于与某些旧软件不兼容,尚未在其服务器上安装 SP1。

© . All rights reserved.