C# 如何避免ASP.NET MVC中由于不区分大小写的URL和默认值而出现重复内容?

C# 如何避免ASP.NET MVC中由于不区分大小写的URL和默认值而出现重复内容?,c#,asp.net,asp.net-mvc,razor,C#,Asp.net,Asp.net Mvc,Razor,编辑:现在我需要真正解决这个问题,我做了更多 调查并提出了一个解决方案 减少重复的事情的数量 内容。我发布了详细的代码 我的博客上的示例: 第一篇帖子——如果我把它标错了或者贴错了标签,那就轻松一点:p 在微软新的ASP.NET MVC框架中,似乎有两件事可能会导致您的内容在多个URL上被提供(这是谷歌的惩罚,并会导致您的PageRank被拆分): 不区分大小写的URL 默认URL 您可以将默认控制器/操作设置为向域根目录发出请求。假设我们选择HomeController/Index。最后,

编辑:现在我需要真正解决这个问题,我做了更多 调查并提出了一个解决方案 减少重复的事情的数量 内容。我发布了详细的代码 我的博客上的示例:

第一篇帖子——如果我把它标错了或者贴错了标签,那就轻松一点:p

在微软新的ASP.NET MVC框架中,似乎有两件事可能会导致您的内容在多个URL上被提供(这是谷歌的惩罚,并会导致您的PageRank被拆分):

  • 不区分大小写的URL
  • 默认URL
您可以将默认控制器/操作设置为向域根目录发出请求。假设我们选择HomeController/Index。最后,我们将使用以下URL提供相同的内容:

  • mydomain.com/
  • mydomain.com/Home/Index
现在,如果人们开始链接到这两个页面,那么PageRank将被拆分。谷歌也会考虑复制内容并惩罚其中之一,以避免重复结果。

除此之外,URL不区分大小写,因此我们实际上也为这些URL获取相同的内容:

  • mydomain.com/Home/Index
  • mydomain.com/home/index
  • mydomain.com/Home/index
  • mydomain.com/home/Index
  • (名单还在继续)
所以,问题是。。。我如何避免这些处罚?我想:

  • 将默认操作的所有请求(301状态)重定向到同一url
  • 所有URL都区分大小写

可能吗?

除了在这里发帖外,我还发电子邮件给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等方法的链接生成更改为匹配。在这件事上,我显然会听从斯科特格的。不过,我也谦虚地提出了解决这个问题的办法

将以下代码添加到全局.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();
    }
}

一个好问题

我相信有更好的答案。如果在页眉中放置规范链接,如:

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

然后谷歌只在他们的搜索结果中显示规范页面,更重要的是,谷歌所有的好东西都会进入该页面,而不会受到惩罚。

就像你一样;除了我不愿意接受全小写的URL限制,也不喜欢
规范的
方法(好吧,这很好,但不是它自己)

我找不到解决办法,所以我们找了一个

使用它非常简单:控制器类中的每个GET方法只需在开始时添加这一行:

Seo.SeoRedirect(this);
SEO重写类自动使用C#5.0的Caller Info属性来完成繁重的工作,使上面的代码严格地复制和粘贴

正如我在链接的SO Q&A中提到的,我正在研究一种将其转换为属性的方法,但现在,它完成了工作


该代码将强制URL使用一个大小写。大小写将与控制器方法的名称相同-您可以选择是要全部大写、全部小写,还是两者兼而有之(CamelCase适合URL)。它将对不区分大小写的匹配发出301重定向,并将结果缓存在内存中以获得最佳性能。它还将重定向尾部反斜杠(对索引列表强制,否则强制关闭),并删除通过默认方法名访问的重复内容(
index
,在股票ASP.NET MVC应用程序中).

我真的不知道8年后你会有什么感觉,但现在ASP MVC 5支持属性路由,以便于记住路由,并解决SEO友好站点的重复内容问题

加上 routes.mapmvcattributteroutes();在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();
    }
碰撞

MVC5现在只支持生成小写URL和公共尾随斜杠策略

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.LowercaseUrls = true;
        routes.AppendTrailingSlash = false;
     }
另外,我的应用程序,以避免在不同的域/Ip/字母大小写等重复内容

我倾向于基于主域-协议-控制器-语言-操作

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。

基于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是个好主意。

据我所知,这有一个潜在的缺点。打开Chrome(或其他具有良好调试功能的浏览器),注意所有对图像、样式表、javascript等的请求都会被重定向(假设您将它们放在名为“Content”的文件夹或其他文件夹中)。您不希望浏览器必须将对此类资产的请求数量增加一倍,因此请确保它们是小写的,或者不要发送301s,因为这些链接实际上不是路由。如果它们位于大写文件夹中,请确保您没有重定向图像/样式表/等的请求,因为这将创建更多的往返,这意味着访问者会有更多的延迟,站点会有更多的CPU/带宽。当然,这是一个选项,但首先只有一个可能的url更好,而且不依赖于正在构建的支持该url的搜索引擎
filters.Add(new RedirectFilterAttribute());