¿Cómo puedo evitar contenido duplicado en ASP.NET MVC debido a URL y valores predeterminados que no distinguen entre mayúsculas y minúsculas?

StackOverflow https://stackoverflow.com/questions/170900

  •  05-07-2019
  •  | 
  •  

Pregunta

  

Editar : ahora necesito resolver este problema de verdad, hice un poco más   investigación y se le ocurrió una   Número de cosas para reducir duplicados.   contenido. Publiqué el código detallado   ejemplos en mi blog: Reducing   Contenido duplicado con ASP.NET MVC

Primera publicación: vaya fácil si marqué esto mal o lo etiqueté mal: P

En el nuevo marco ASP.NET MVC de Microsoft, parece que hay dos cosas que podrían hacer que su contenido se publique en varias URL (algo por lo que Google penaliza y hará que su PageRank se divida entre ellas):

  • URL que no distinguen entre mayúsculas y minúsculas
  • URL predeterminada

Puede configurar el controlador / acción predeterminado para que se atiendan las solicitudes a la raíz de su dominio. Digamos que elegimos HomeController / Index. Terminamos con las siguientes URL que ofrecen el mismo contenido:

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

Ahora, si la gente comienza a enlazar con ambos, entonces PageRank se dividirá. Google también lo consideraría contenido duplicado y penalizaría a uno de ellos para evitar duplicados en sus resultados.

Además de esto, las URL no distinguen entre mayúsculas y minúsculas, por lo que también obtenemos el mismo contenido para estas URL:

  • mydomain.com/Home/Index
  • midominio.com/home/index
  • mydomain.com/Home/index
  • mydomain.com/home/Index
  • (la lista continúa)

Entonces, la pregunta ... ¿Cómo evito estas sanciones? Me gustaría:

  • Todas las solicitudes para que la acción predeterminada se redirija (estado 301) a la misma URL
  • Todas las URL distinguen entre mayúsculas y minúsculas

¿Posible?

¿Fue útil?

Solución

Bump!

MVC 5 ahora admite producir solo urls en minúsculas y una política de barra inclinada común.

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

También en mi aplicación para evitar contenido duplicado en diferentes dominios / Ip / letras, etc. ...

  

http://yourdomain.com/en

     

https://yourClientIdAt.YourHostingPacket.com/

Tiendo a generar URLs canónicas basadas en un Dominio primario - Protocolo - Controlador - Idioma - Acción

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);
}

Luego, puede utilizar la respuesta de @Gabe Sumner para redirigir a la url canónica de su acción si la url de solicitud actual no coincide.

Otros consejos

Yo también estaba trabajando en esto. Obviamente voy a ceder a ScottGu en esto. Aunque también ofrezco humildemente mi solución a este problema.

Agregue el siguiente código a 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();
    }
}

¡Una gran pregunta!

Además de publicar aquí, le envié un correo electrónico a ScottGu para ver si tenía una buena respuesta. Dio una muestra para agregar restricciones a las rutas, por lo que solo podría responder a urls en minúsculas:

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());
    }

Y en el método de registro de rutas:

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() }
    );
}

Es un comienzo, pero querría poder cambiar la generación de enlaces de métodos como Html.ActionLink y RedirectToAction para que coincidan.

Creo que hay una mejor respuesta a esto. Si coloca un enlace canónico en el encabezado de su página, como:

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

Luego, Google solo muestra la página canónica en sus resultados y, lo que es más importante, toda la bondad de Google va a esa página sin penalización.

Al igual que usted, tuve la misma pregunta ; excepto que no estaba dispuesto a conformarme con una limitación de URL en minúsculas, y tampoco me gustó el enfoque canonical (bueno, es bueno pero no por sí solo).

No pude encontrar una solución, por lo que escribimos y trabajamos con código abierto a redirect class .

Su uso es bastante sencillo: cada método GET en las clases del controlador debe agregar solo una línea al comienzo:

Seo.SeoRedirect(this);

La clase de reescritura SEO usa automáticamente los atributos de Información de llamadas de C # 5.0 para hacer el trabajo pesado, haciendo que el código de arriba sea estrictamente copiar y pegar.

Como mencioné en el SO Q & amp; A vinculado, estoy trabajando en una forma de convertir esto en un atributo, pero por ahora, hace el trabajo.

El código forzará un caso para la URL. El caso será el mismo que el nombre del método del controlador: usted elige si desea todas las mayúsculas, todas más bajas o una combinación de ambas (CamelCase es bueno para las URL). Emitirá redireccionamientos 301 para coincidencias que no distingan entre mayúsculas y minúsculas, y almacena en caché los resultados en la memoria para un mejor rendimiento. También redirigirá las barras diagonales finales (impuestas para las listas de índices; de lo contrario, se eliminará) y eliminará el contenido duplicado al que se accede mediante el nombre del método predeterminado ( Index en una aplicación MVC ASP.NET de valores).

Realmente no sé cómo se sentirá después de 8 años, pero ahora ASP MVC 5 es compatible con el enrutamiento de atributos para rutas fáciles de recordar y para resolver problemas de contenido duplicado para sitios SEO Friendly

solo agrega route.MapMvcAttributeRoutes (); en su RouteConfig y luego defina una y única ruta para cada acción como

    [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();
    }

Basado en la respuesta de Gabe Sumner, pero sin redireccionamientos para JS, imágenes y otro contenido. Funciona solo en acciones de controlador. La idea es hacer la redirección más adelante en la tubería cuando ya sabemos que es una ruta. Para esto podemos usar un 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);
    }
}

Tenga en cuenta que el filtro anterior no redirige ni cambia la carcasa de la cadena de consulta.

Luego vincule el ActionFilter globalmente a todas las acciones agregándolo a GlobalFilterCollection.

filters.Add(new RedirectFilterAttribute());

Es una buena idea seguir configurando la propiedad LowercaseUrls en true en RouteCollection.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top