由于不区分大小写的 URL 和默认值,如何避免 ASP.NET MVC 中的重复内容?
Posted
技术标签:
【中文标题】由于不区分大小写的 URL 和默认值,如何避免 ASP.NET MVC 中的重复内容?【英文标题】:How can I avoid duplicate content in ASP.NET MVC due to case-insensitive URLs and defaults? 【发布时间】:2010-09-15 07:33:18 【问题描述】:编辑:现在我需要真正解决这个问题,我做了更多 调查并提出了一个 减少重复的事情的数量 内容。我发布了详细的代码 我博客上的示例:Reducing Duplicate Content with ASP.NET MVC
第一篇文章 - 如果我标记错误或标记错误,请轻松:P
在 Microsoft 的新 ASP.NET MVC 框架中,似乎有两件事可能会导致您的内容在多个 URL 上提供(Google 会惩罚这一点,并将导致您的 PageRank 在它们之间拆分):
不区分大小写的 URL 默认网址您可以设置默认控制器/操作来为您的域根目录的请求提供服务。假设我们选择 HomeController/Index。我们最终会得到以下提供相同内容的 URL:
mydomain.com/ mydomain.com/Home/Index现在,如果人们开始链接到这两个,那么 PageRank 将被拆分。谷歌也会认为它重复内容并惩罚其中之一以避免结果重复。
除此之外,网址不区分大小写,因此我们实际上也为这些网址获得了相同的内容:
mydomain.com/Home/Index mydomain.com/home/index mydomain.com/Home/index mydomain.com/home/Index (不胜枚举)那么,问题是……我该如何避免这些处罚?我想要:
默认操作的所有请求都将被重定向(301 状态)到相同的 url 所有 URL 都区分大小写可能吗?
【问题讨论】:
如果图像/样式表/等位于大写文件夹中,请确保您没有重定向请求,因为这会产生更多的往返,这意味着您的访问者会有更多的延迟等等您网站的 CPU/带宽。 【参考方案1】:我也在做这个。在这点上,我显然会听从 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();
一个好问题!
【讨论】:
据我所知,这有一个潜在的缺点。打开 Chrome(或其他具有良好调试功能的浏览器)并注意所有对图像、样式表、javascript 等的请求都被重定向(假设您将它们放在名为“Content”或其他的文件夹中。)您不希望浏览器必须将此类资产的请求数量增加一倍,因此要么确保它们是小写的,要么不要为实际上不是路由的链接发送 301。【参考方案2】:除了在这里发帖外,我还给 ScottGu 发了电子邮件,看看他是否有好的回应。他给出了一个为路由添加约束的示例,所以你只能响应小写的 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 等方法更改链接的生成以匹配。
【讨论】:
【参考方案3】:撞!
MVC 5 现在支持仅生成小写 URL 和常见的尾部斜杠策略。
public static void RegisterRoutes(RouteCollection routes)
routes.LowercaseUrls = true;
routes.AppendTrailingSlash = false;
也在我的应用程序上避免在不同的域/IP/字母大小写等上重复内容...
http://yourdomain.com/en
https://yourClientIdAt.YourHostingPacket.com/
我倾向于基于 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);
然后,如果当前请求 url 不匹配,您可以使用 @Gabe Sumner 的 答案重定向到您操作的规范 url。
【讨论】:
酷;将其更改为已接受的答案,因为它现在看起来更相关:-)【参考方案4】:我相信对此有更好的答案。如果您在页面标题中放置一个规范链接,例如:
<link rel="canonical" href="http://mydomain.com/Home/Index"/>
然后 google 只在他们的结果中显示规范页面,更重要的是,所有 google 的优点都会进入该页面而不会受到惩罚。
【讨论】:
当然是一个选项,但首先只有一个可能的 url 更好,并且不依赖于构建的搜索引擎来支持这一点:-) 为什么更好?我认为有很多很好的商业理由让多个网址提供同一个页面。也不要忘记为什么开始这篇文章 - 因为谷歌会惩罚重复的内容。他们支持这个链接正是因为他们不想惩罚那些出于正当理由复制内容的人。【参考方案5】:和你一样,I had the same question;除了我不愿意接受全小写的 URL 限制,也不喜欢 canonical
方法(嗯,它很好,但不是单独的)。
我找不到解决方案,所以我们wrote and open-sourced 和redirect class。
使用起来很简单:控制器类中的每个 GET 方法只需要在开头添加这一行:
Seo.SeoRedirect(this);
SEO 重写类自动使用 C# 5.0 的 Caller Info 属性来完成繁重的工作,使上面的代码严格复制和粘贴。
正如我在链接的 SO Q&A 中提到的那样,我正在研究一种将其转换为属性的方法,但现在,它可以完成工作。
代码将强制 URL 使用一种大小写。大小写与控制器方法的名称相同 - 您可以选择是否要全部大写、全部小写或两者混合(CamelCase 适合 URL)。它将针对不区分大小写的匹配发出 301 重定向,并将结果缓存在内存中以获得最佳性能。它还将重定向尾随反斜杠(对索引列表强制执行,否则强制执行)并删除通过默认方法名称访问的重复内容(股票 ASP.NET MVC 应用程序中的Index
)。
【讨论】:
【参考方案6】:我真的不知道 8 年后你会有什么感觉,但是现在 ASP MVC 5 支持属性路由,以便于记住路由并解决 SEO 友好网站的重复内容问题
只需添加 路线.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();
【讨论】:
而对于其他路由的增强,也可以使用【参考方案7】:基于 Gabe Sumner 的回答,但没有针对 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());
在 RouteCollection 上仍将 LowercaseUrls 属性设置为 true 是个好主意。
【讨论】:
以上是关于由于不区分大小写的 URL 和默认值,如何避免 ASP.NET MVC 中的重复内容?的主要内容,如果未能解决你的问题,请参考以下文章