OpenU.Ru
Сайты, разработанные на паттерне MVC в ASP.NET Framework имеют особенность отдавать одинаковое содержимое с HTTP-кодом 200 по разным url, если вызывается действие по-умолчанию контроллера (Index) или сам контроллер по-умолчанию (home). Например, действие Index контроллера HomeController сработает и сформирует одинаковую страницу представления Index.cshtml при обращении сразу как минимум, по трём url-адресам: example.com, example.com/Home и example.com/Home/Index. Index контроллера AboutController — по двум: example.com/About и example.com/About/Index. Это очень плохо в плане поисковой оптимизации, т.к. создаются страницы-дубли, и нужно чтобы либо страница отвечала двухсотым кодом только по одному адресу, а с остальных либо отдавала http ошибку 404 (ресурс не найден), либо 301 (ресурс перемещён навсегда). Выберем второй вариант и будем перенаправлять 301-м редиректом со страниц Index или Home на корневую папку. Существует несколько методов, но во-первых следует перевести все url в нижний регистр, чтобы Index в адресной строке превратился в index.
Переопределим метод RegisterRoutes класса RouteConfig следующим образом:
public static void RegisterRoutes(RouteCollection routes) { routes.IgnoreRoute("{resource}.axd/{*pathInfo}"); routes.MapRoute( name: "IndexRedirect", url: "{controller}/Index", defaults: new { controller = "Home", action = "Index", NeedRedirectFromIndex = true } ); routes.MapRoute( name: "HomeRedirect", url: "Home/", defaults: new { controller = "Home", action = "Index", NeedRedirectFromIndex = true } ); routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
Тут мы указываем, что если url заканчивается на Index или Home, то в контроллер также передаётся параметр NeedRedirectFromIndex. Далее, контроллер должен проверить этот параметр и в случае его наличия вызвать переадресацию на самого себя с пустым параметром. Для этого перепишем метод Index контроллера:
public ActionResult Index(bool? NeedRedirectFromIndex) { //редирект с папок Home/Index if (NeedRedirectFromIndex.HasValue && NeedRedirectFromIndex.Value) return RedirectToActionPermanent("Index", new { NeedRedirectFromIndex = null as object }); return View(); }
Теперь при обращении к папке home/index будет перенаправление в корневую папку сайта. У этого подхода, как минимум, 2 недостатка. Во-первых, нужно так или иначе модифицировать все методы Index всех контроллеров, для которых мы желаем производить перенаправление. Во-вторых, при построении ссылок, например, с помощью выражения ActionLink нужно добавлять пустое значение RedirectToActionPermanent в качестве параметра:
@Html.ActionLink("Главная", "Index", "Home", new { RedirectToActionPermanent = null as object }, null)
Иначе адреса будут формироваться в виде controller/index, а с них уже будет происходить перенаправление, что тоже не есть хорошо не только для поисковой оптимизации, но и для нагрузки на сервер
Оставляем маршруты и контроллеры в изначальном виде (по умолчанию) и опишем метод Application_BeginRequest класса MvcApplication примерно следующим образом (файл global.asax):
protected void Application_BeginRequest(object sender, EventArgs e) { //Не редиректим на нижний регистр метод "post" или images/css/js bool isGet = HttpContext.Current.Request.RequestType.ToLowerInvariant().Contains("get"); if (isGet && HttpContext.Current.Request.Url.AbsolutePath.Contains(".") == false) { bool NeedRedirect = false; string lowercaseURL = (Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath); if (Regex.IsMatch(lowercaseURL, @"[A-Z]")) { //не меняем регистр параметров lowercaseURL = lowercaseURL.ToLower() + HttpContext.Current.Request.Url.Query; NeedRedirect = true; } //редирект с /index на уровень вверх... if (Regex.IsMatch(lowercaseURL, @"/index[/]?$")) { lowercaseURL = Regex.Replace(lowercaseURL, "/index[/]?$", RouteTable.Routes.AppendTrailingSlash ? "/" : ""); NeedRedirect = true; } //редирект с /home на уровень вверх... if (Regex.IsMatch(lowercaseURL, @"/home[/]?$")) { lowercaseURL = Regex.Replace(lowercaseURL, "/home[/]?$", RouteTable.Routes.AppendTrailingSlash ? "/" : ""); NeedRedirect = true; } if (NeedRedirect) { Response.Clear(); Response.Status = "301 Moved Permanently"; Response.AddHeader("Location", lowercaseURL); Response.End(); } } }
В листинге выше уже сразу дополнительно описано преобразование url в нижний регистр и предусмотрена переадресация на url со слэшем на конце или без, в зависимости от выбранной политики с помощью признака свойства RouteTable.Routes.AppendTrailingSlash. Недостатком подхода остается необходимость контроля построения url. Например, для маршрута по умолчанию:
routes.MapRoute( name: "Default", url: "{controller}/{action}/{id}", defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional } );
в случае, если в качестве id будет передано значение «Index» или «home», то сработает перадресация и параметр никогда не будет передан в контроллер. Понятно, что в параметре Id таких значений, скорее всего, передано не будет, но если в качестве параметра выступает строковое значение (например ЧПУ-url вида {controller}/{action}/{id}/{url}) — то вполне вероятно. В качестве крайнего решения можно предопределить имя метода действия по-умолчанию на какое-нибудь уникальное название (комбинацию символов), которое никогда не будет передано в качестве параметра. Либо доработать условия переадресации метода Application_BeginRequest на соблюдение уровней вложенностей адресов и, возможно, наложения дополнительных условий проверки url-ов в случае сложной адресации, когда в зависимости от условия вхождения строки в url уровень вложенности может быть различным.
Чтобы переадресовать с папки Home сайта в папку home/index, нужно в файле Web.config в секции <configuration> — <system.webServer> — <rewrite> — <rules> добавить правило:
<rule name="Redirect HomeIndex" stopProcessing="true"> <match url="home[/]?$" /> <action type="Redirect" url="home/index" redirectType="Permanent" /> </rule>
Аналогично можно сделать и другие переадресации, если есть возможность правильно написать регулярные выражения и условия.