使用路由操作URL

时间:2015-05-06 08:21:41

标签: asp.net-mvc asp.net-routing

在我的网站中,我定义了以下路线:

routes.MapRoute(
   name: "Specific Product",
   url: "product/{id}",
   defaults: new { controller = "", action = "Index", id = UrlParameter.Optional }
);

这样我希望客户能够添加产品的ID并转到产品页面。

SEO顾问说,如果我们可以在URL上添加产品描述(如产品名称或其他内容)会更好。因此,URL应如下所示:

  

/产品/我的 - 冷却 - 产品名称/ 123

  

/产品/我的 - 冷却 - 产品名称-123

当然描述存储在db中,我不能用url重写(或者我可以吗?)

我应该在控制器上添加重定向(这似乎可以完成工作,但它感觉不对)

在我检查过的几个网站上,他们确实回复了301 Moved Permanently。这真的是最好的方法吗?

更新

根据Stephen Muecke的评论,我查看了SO上发生的事情。

建议的网址是我自己的Manipulate the url using routing,我打开控制台查看任何重定向。这是一个截图:

SO-301-response

1 个答案:

答案 0 :(得分:0)

所以,首先非常特别感谢 @StephenMuecke 给出了slug的提示以及他建议的网址。

我想发布我的方法,该方法是该网址和其他几篇文章的混合。

我的目标是让用户输入一个网址:

  

/产品/ 123

当页面加载以在地址栏中显示如下内容:

  

/产品/ MY-要命产品名称-123

我检查了几个有此行为的网站,似乎在我检查的所有内容中都使用了301 Moved Permanently响应。即便如我在问题中所示,使用301来添加问题的标题。我认为会有一种不同的方法,不需要第二次往返......

所以我在这种情况下使用的总解决方案是:

  1. 我创建了一个SlugRouteHandler类,如下所示:

    public class SlugRouteHandler : MvcRouteHandler
    {
        protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            var url = requestContext.HttpContext.Request.Path.TrimStart('/');
    
            if (!string.IsNullOrEmpty(url))
            {
                var slug = (string)requestContext.RouteData.Values["slug"];
                int id;
    
                //i care to transform only the urls that have a plain product id. If anything else is in the url i do not mind, it looks ok....
                if (Int32.TryParse(slug, out id))
                {
                    //get the product from the db to get the description
                    var product = dc.Products.Where(x => x.ID == id).FirstOrDefault();
                    //if the product exists then proceed with the transformation. 
                    //if it does not exist then we could addd proper handling for 404 response here.
                    if (product != null)
                    {
                        //get the description of the product
                        //SEOFriendly is an extension i have to remove special characters, replace spaces with dashes, turn capital case to lower and a whole bunch of transformations the SEO audit has requested
                        var description = String.Concat(product.name, "-", id).SEOFriendly(); 
                        //transform the url
                        var newUrl = String.Concat("/product/",description);
                        return new RedirectHandler(newUrl);
                    }
                }
    
            }
    
            return base.GetHttpHandler(requestContext);
        }
    
    }
    
  2. 从上面我还需要创建一个RedirectHandler类来处理重定向。这实际上是here

    的直接副本
    public class RedirectHandler : IHttpHandler
    {
        private string newUrl;
    
        public RedirectHandler(string newUrl)
        {
            this.newUrl = newUrl;
        }
    
        public bool IsReusable
        {
            get { return true; }
        }
    
        public void ProcessRequest(HttpContext httpContext)
        {
            httpContext.Response.Status = "301 Moved Permanently";
            httpContext.Response.StatusCode = 301;
            httpContext.Response.AppendHeader("Location", newUrl);
            return;
        }
    }
    
  3. 通过这2个课程,我可以将产品ID转换为SEO友好的网址。

    为了使用这些我需要修改我的路线以使用SlugRouteHandler类,这导致:

    1. 从路径

      调用SlugRouteHandler课程
      routes.MapRoute(
         name: "Specific Product",
         url: "product/{slug}",
         defaults: new { controller = "Product", action = "Index" }
      ).RouteHandler = new SlugRouteHandler();
      
    2. 使用评论中提到的link @StephenMuecke

      我们需要找到一种方法将新的SEO友好网址映射到我们的实际控制器。我的控制器接受一个整数id,但url将提供一个字符串。

      1. 我们需要创建一个Action过滤器来处理在调用控制器之前传递的新参数

        public class SlugToIdAttribute : ActionFilterAttribute
        {
        
            public override void OnActionExecuting(ActionExecutingContext filterContext)
            {
                var slug = filterContext.RouteData.Values["slug"] as string;
                if (slug != null)
                {
                    //my transformed url will always end in '-1234' so i split the param on '-' and get the last portion of it. That is my id. 
                    //if an id is not supplied, meaning the param is not ending in a number i will just continue and let something else handle the error
                    int id;
                    Int32.TryParse(slug.Split('-').Last(), out id);
                    if (id != 0)
                    {
                        //the controller expects an id and here we will provide it
                        filterContext.ActionParameters["id"] = id;
                    }
                }
                base.OnActionExecuting(filterContext);
            }
        }
        
      2. 现在发生的事情是控制器将能够接受以数字结尾的非数字id并提供其视图而不修改控制器的内容。我们只需要在控制器上添加filter属性,如下一步所示。

        我真的不在乎产品名称是否实际上是产品名称。您可以尝试获取以下网址:

          

        \产品\ 123

             

        \产品\产品名称-123

             

        \产品\另一副产物-123

             

        \产品\约翰-DOE-123

        并且您仍会获得ID为123的产品,但网址不同。

        1. 下一步是让控制器知道它必须使用特殊的文件管理器

          [SlugToId]
          public ActionResult Index(int id)
          {
          }