Как избежать дублирования контента в ASP.NET MVC из-за URL-адресов, нечувствительных к регистру, и значений по умолчанию?
-
05-07-2019 - |
Вопрос
Редактировать:Теперь мне нужно решить эту проблему по-настоящему, я сделал немного больше расследование и придумал с количество вещей для уменьшения дубликатов содержание.Я выложил подробный код образцы в моем блоге: Сокращение Дублирование контента с помощью ASP.NET MVC
Первый пост. Будьте проще, если я неправильно его разметил или неправильно отметил. :P
В новой платформе ASP.NET MVC от Microsoft, похоже, есть две вещи, которые могут привести к тому, что ваш контент будет отображаться по нескольким URL-адресам (за что Google наказывает и приведет к разделению вашего PageRank между ними):
- URL-адреса без учета регистра
- URL-адрес по умолчанию
Вы можете установить контроллер/действие по умолчанию для обработки запросов к корню вашего домена.Допустим, мы выбираем HomeController/Index.В итоге мы получаем следующие URL-адреса, предоставляющие один и тот же контент:
- mydomain.com/
- mydomain.com/Главная/Индекс
Теперь, если люди начнут ссылаться на оба из них, PageRank будет разделен.Google также будет считать это дублирующим контентом и наказывать одного из них, чтобы избежать дублирования результатов.
Кроме того, URL-адреса не чувствительны к регистру, поэтому мы фактически получаем один и тот же контент для этих URL-адресов:
- mydomain.com/Главная/Индекс
- мойдомен.com/home/index
- mydomain.com/Home/index
- mydomain.com/home/Index
- (список можно продолжить)
Итак, вопрос...Как мне избежать этих наказаний?Я хотел бы:
- Все запросы на действие по умолчанию будут перенаправлены (статус 301) на один и тот же URL-адрес.
- Все URL-адреса должны быть чувствительны к регистру
Возможный?
Решение
Ударяться!
МВК 5 Теперь поддерживается создание только строчных URL-адресов и общая политика косой черты в конце.
public static void RegisterRoutes(RouteCollection routes)
{
routes.LowercaseUrls = true;
routes.AppendTrailingSlash = false;
}
Также в моем приложении, чтобы избежать дублирования контента в разных доменах/IP-адресах/регистре букв и т. д.
Я склонен создавать канонические URL-адреса на основе Первичныйдомен - Протокол - Контроллер - Язык - Действие
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);
}
Тогда вы можете использовать @Гейб Самнер ответ для перенаправления на канонический URL-адрес вашего действия, если текущий URL-адрес запроса не соответствует ему.
Другие советы
Я тоже работал над этим.Я, очевидно, подчинюсь в этом Скотту.Однако я смиренно предлагаю свое решение и этой проблемы.
Добавьте следующий код в 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();
}
}
Отличный вопрос!
Помимо публикации здесь, я отправил электронное письмо Скотту Гу, чтобы узнать, получил ли он хороший ответ.Он привел пример добавления ограничений к маршрутам, чтобы вы могли отвечать только на 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, чтобы они соответствовали.
Я считаю, что на этот вопрос есть лучший ответ.Если вы поместите каноническую ссылку в заголовок страницы, например:
<link rel="canonical" href="http://mydomain.com/Home/Index"/>
Тогда Google показывает в своих результатах только каноническую страницу, и, что более важно, все преимущества Google попадают на эту страницу без каких-либо штрафов.
Как ты, У меня такой же вопрос;за исключением того, что я не хотел соглашаться на ограничение URL-адреса, состоящего только из строчных букв, и мне не нравилось canonical
подход либо (ну, это хорошо, но не само по себе).
Я не смог найти решение, поэтому мы написал и открыл исходный код а класс перенаправления.
Использовать его достаточно просто:каждый метод GET в классах контроллера должен добавить только одну строку в начале:
Seo.SeoRedirect(this);
Класс перезаписи SEO автоматически использует атрибуты информации о вызывающем абоненте C# 5.0 для выполнения тяжелой работы, что делает приведенный выше код строго копируемым и вставляемым.
Как я уже упоминал в связанных вопросах и ответах по SO, я работаю над тем, как преобразовать это в атрибут, но на данный момент он выполняет свою работу.
Код будет принудительно использовать один регистр для URL-адреса.Регистр будет таким же, как и в названии метода контроллера — вы выбираете, хотите ли вы использовать все прописные буквы, все нижние или сочетание того и другого (CamelCase подходит для URL-адресов).Он выдает 301 перенаправление для совпадений без учета регистра и кэширует результаты в памяти для обеспечения максимальной производительности.Он также перенаправляет конечные обратные косые черты (принудительно для списков индексов, в противном случае принудительно отключается) и удаляет дублирующийся контент, доступ к которому осуществляется через имя метода по умолчанию (Index
в стандартном приложении ASP.NET MVC).
я действительно не знаю, как вы будете себя чувствовать через 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();
}
На основе ответа Гейба Самнера, но без перенаправлений для 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.