Управление URL с помощью маршрутизации

На моем сайте я определил следующий маршрут:

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

Таким образом, я хочу, чтобы клиенты могли добавить идентификатор продукта и перейти на страницу продукта.

SEO-консультанты говорят, что было бы лучше, если бы мы могли добавить описание продукта в URL, например, название продукта или что-то в этом роде. Так что URL должен выглядеть примерно так:

/ / Мой-прохладный продукт Название продукта /123

или же

/ / Мой-круто-продукт-имя-123 продукт

Конечно, описание хранится в БД, и я не могу сделать это с помощью перезаписи URL (или я могу?)

Должен ли я добавить перенаправление на моем контроллере (казалось бы, это сделает работу, но это не так)

На нескольких сайтах, которые я проверил, они отвечают 301 Moved Permanently, Это действительно лучший подход?

ОБНОВИТЬ

Согласно Stephen MueckeКомментарий Я проверил, что происходит на SO.

Предлагаемый URL-адрес был моим собственным. Манипулировать URL-адресом с помощью маршрутизации, и я открыл консоль, чтобы увидеть любые перенаправления. Вот скриншот:

ТАК-301-ответ

1 ответ

Решение

Итак, прежде всего, особая благодарность @StephenMuecke за подсказку для слизней, а также за URL, который он предложил.

Я хотел бы опубликовать свой подход, который представляет собой сочетание этого URL и нескольких других статей.

Моя цель состояла в том, чтобы пользователь мог ввести URL-адрес, например:

/ Продукт /123

и когда страница загружается, чтобы показать в адресной строке что-то вроде:

/ / Мой-Awsome продукт-имя-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 класс для обработки перенаправлений. Это на самом деле прямая копия отсюда

    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;
        }
    }
    

С помощью этих 2 классов я могу преобразовать идентификаторы продуктов в оптимизированные для SEO адреса.

Чтобы использовать их, мне нужно изменить маршрут, чтобы использовать SlugRouteHandler класс, который приводит к:

  1. Вызов SlugRouteHandler класс с маршрута

    routes.MapRoute(
       name: "Specific Product",
       url: "product/{slug}",
       defaults: new { controller = "Product", action = "Index" }
    ).RouteHandler = new SlugRouteHandler();
    

Здесь идет использование ссылки @StephenMuecke, упомянутой в его комментарии.

Нам нужно найти способ сопоставить новый SEO-дружественный URL с нашим фактическим контроллером. Мой контроллер принимает целочисленный идентификатор, но 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);
        }
    }
    

Теперь происходит то, что контроллер сможет принимать нечисловой идентификатор, заканчивающийся цифрой, и отображать его без изменения содержимого контроллера. Нам нужно только добавить атрибут фильтра на контроллере, как показано на следующем шаге.

Мне действительно все равно, если название продукта на самом деле название продукта. Вы можете попробовать получить следующие URL:

\ Продукт \ 123

\ Название-продукта-123 продукт \

\ Продукт \ другой продукт-123

\ Продукт \ джон-МЭ-123

и вы все равно получите продукт с идентификатором 123хотя URL разные.

  1. Следующий шаг - сообщить контроллеру, что он должен использовать специальный файлер.

    [SlugToId]
    public ActionResult Index(int id)
    {
    }
    
Другие вопросы по тегам