Как избежать дублирования содержимого в ASP.NET MVC из-за нечувствительных к регистру URL-адресов и значений по умолчанию? - PullRequest
24 голосов
/ 04 октября 2008

Редактировать : Теперь мне нужно решить эту проблему по-настоящему, я сделал немного больше расследование и придумал количество вещей, чтобы уменьшить дубликат содержание. Я разместил подробный код Образцы в моем блоге: Уменьшение Дублированный контент с ASP.NET MVC

Первый пост - будьте спокойны, если я пометил это неправильно или пометил это плохо: P

В новой платформе Microsoft ASP.NET MVC от Microsoft кажется, что есть две вещи, которые могут привести к тому, что ваш контент будет обрабатываться по нескольким URL-адресам (за что Google наказывает и заставит ваш PageRank разделиться на них):

  • URL-адреса без учета регистра
  • URL по умолчанию

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

  • mydomain.com /
  • mydomain.com / Home / Index

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

Кроме того, URL-адреса не чувствительны к регистру, поэтому мы фактически получаем одинаковое содержимое и для этих URL-адресов:

  • mydomain.com / Home / Index
  • mydomain.com / дом / индекс
  • mydomain.com / Главная / индекс
  • mydomain.com / дом / Индекс
  • (список можно продолжить)

Итак, вопрос ... Как мне избежать этих штрафов? Я хотел бы:

  • Все запросы на действие по умолчанию для перенаправления (статус 301) на тот же URL-адрес
  • Все URL должны быть чувствительными к регистру

Возможно

Ответы [ 7 ]

11 голосов
/ 05 октября 2008

Я тоже работал над этим. Я, очевидно, буду откладывать на ScottGu по этому вопросу. Я также смиренно предлагаю свое решение этой проблемы.

Добавьте следующий код в global.asax :

protected void Application_BeginRequest(Object sender, EventArgs e)
{
    // If upper case letters are found in the URL, redirect to lower case URL.
    if (Regex.IsMatch(HttpContext.Current.Request.Url.ToString(), @"[A-Z]") == true)
    {
        string LowercaseURL = HttpContext.Current.Request.Url.ToString().ToLower();

        Response.Clear();
        Response.Status = "301 Moved Permanently";
        Response.AddHeader("Location",LowercaseURL);
        Response.End();
    }
}

Отличный вопрос!

9 голосов
/ 05 октября 2008

Помимо публикации здесь, я отправил Скотту письмо по электронной почте, чтобы узнать, получился ли у него хороший ответ. Он привел пример добавления ограничений к маршрутам, чтобы вы могли отвечать только на строчные URL:

public class LowercaseConstraint : IRouteConstraint
{
    public bool Match(HttpContextBase httpContext, Route route,
            string parameterName, RouteValueDictionary values,
            RouteDirection routeDirection)
    {
        string value = (string)values[parameterName];

        return Equals(value, value.ToLower());
    }

И в реестре маршрутов метод:

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        "Default",                                              // Route name
        "{controller}/{action}/{id}",                           // URL with parameters
        new { controller = "home", action = "index", id = "" },
        new { controller = new LowercaseConstraint(), action = new LowercaseConstraint() }
    );
}

Это только начало, но я бы хотел изменить генерацию ссылок с помощью таких методов, как Html.ActionLink и RedirectToAction, чтобы они соответствовали.

4 голосов
/ 22 декабря 2016

Bump!

MVC 5 Теперь поддерживается создание только строчных URL-адресов и общей политики конечной косой черты.

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.LowercaseUrls = true;
        routes.AppendTrailingSlash = false;
     }

Также в моем заявлении, чтобы избежать дублирования контента на разных доменах / Ip / Letter Casing и т.д ...

http://yourdomain.com/en

https://yourClientIdAt.YourHostingPacket.com/

Я склонен создавать канонические URL-адреса на основе PrimaryDomain - Протокол - Контроллер - Язык - Действие

public static String GetCanonicalUrl(RouteData route,String host,string protocol)
{
    //These rely on the convention that all your links will be lowercase! 
    string actionName = route.Values["action"].ToString().ToLower();
    string controllerName = route.Values["controller"].ToString().ToLower();
    //If your app is multilanguage and your route contains a language parameter then lowercase it also to prevent EN/en/ etc....
    //string language = route.Values["language"].ToString().ToLower();
    return String.Format("{0}://{1}/{2}/{3}/{4}", protocol, host, language, controllerName, actionName);
}

Тогда вы можете использовать @ Gabe Sumner's answer, чтобы перенаправить на канонический URL вашего действия, если текущий URL-адрес запроса не соответствует ему.

2 голосов
/ 23 июня 2012

Я считаю, что есть лучший ответ на это. Если вы поместите каноническую ссылку в заголовок страницы, например:

<link rel="canonical" href="http://mydomain.com/Home/Index"/>

Тогда Google показывает только каноническую страницу в своих результатах, и что более важно, все гугл-блага переходят на эту страницу без штрафа.

1 голос
/ 06 ноября 2012

Как и вы, У меня был такой же вопрос ; за исключением того, что я не желал соглашаться на ограничение URL-адреса в нижнем регистре, и мне не понравился подход canonical (ну, это хорошо, но не само по себе).

Я не смог найти решение, поэтому мы написали и с открытым исходным кодом a класс перенаправления .

Использовать его достаточно просто: каждый метод GET в классах контроллера должен добавить только одну строку в начале:

Seo.SeoRedirect(this);

Класс перезаписи SEO автоматически использует атрибуты Caller Info в C # 5.0 для выполнения тяжелой работы, делая приведенный выше код строго копирующим и вставляющим.

Как я упоминал в связанных вопросах и ответах, я работаю над тем, как преобразовать это в атрибут, но пока он выполняет свою работу.

Код форсирует один случай для URL. Регистр будет таким же, как и имя метода контроллера - вы выбираете, хотите ли вы использовать все заглавные буквы, все нижние или их комбинацию (CamelCase подходит для URL-адресов). Он выдаст 301 перенаправлений для совпадений без учета регистра и кэширует результаты в памяти для лучшей производительности. Он также перенаправляет завершающие обратные косые черты (принудительно для списков индексов, принудительно отключается в противном случае) и удаляет дублированный контент, доступ к которому осуществляется через имя метода по умолчанию (Index в стандартном приложении ASP.NET MVC).

0 голосов
/ 03 августа 2018

На основании ответа от Гейба Самнера, но без перенаправлений для JS, изображений и другого контента. Работает только на действиях контроллера. Идея состоит в том, чтобы сделать перенаправление позже в конвейере, когда мы уже знаем его маршрут. Для этого мы можем использовать ActionFilter.

public class RedirectFilterAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var url = filterContext.HttpContext.Request.Url;
        var urlWithoutQuery = url.GetLeftPart(UriPartial.Path);
        if (Regex.IsMatch(urlWithoutQuery, @"[A-Z]"))
        {
            string lowercaseURL = urlWithoutQuery.ToString().ToLower() + url.Query;
            filterContext.Result = new RedirectResult(lowercaseURL, permanent: true);
        }

        base.OnActionExecuting(filterContext);
    }
}

Обратите внимание, что фильтр выше не перенаправляет и не изменяет регистр для строки запроса.

Затем привяжите ActionFilter глобально ко всем действиям, добавив его в GlobalFilterCollection.

filters.Add(new RedirectFilterAttribute());

Рекомендуется установить для свойства LowercaseUrls значение true в RouteCollection.

0 голосов
/ 26 января 2016

Я действительно не знаю, как вы будете себя чувствовать через 8 лет, но теперь ASP MVC 5 поддерживает маршрутизацию атрибутов для удобства запоминания маршрутов и решения проблем с дублированным контентом для сайтов, дружественных к SEO

просто добавь routes.MapMvcAttributeRoutes (); в вашем RouteConfig и затем определите один-единственный маршрут для каждого действия, например

    [Route("~/")]
    public ActionResult Index(int? page)
    {
        var query = from p in db.Posts orderby p.post_date descending select p;
        var pageNumber = page ?? 1;
        ViewData["Posts"] = query.ToPagedList(pageNumber, 7);         
        return View();
    }
    [Route("about")]
    public ActionResult About()
    {
        return View();
    }
    [Route("contact")]
    public ActionResult Contact()
    {
        return View();
    }
    [Route("team")]
    public ActionResult Team()
    {
        return View();
    }
    [Route("services")]
    public ActionResult Services()
    {
        return View();
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...