ASP.NET MVC, enrutamiento de URL: longitud máxima de ruta (URL)

El escenario

Tengo una aplicación donde tomamos la estructura de la URL de la cadena de consulta:

?x=1&y=2&z=3&a=4&b=5&c=6 

y lo cambió a una estructura de ruta:

 /x/1/y/2/z/3/a/4/b/5/c/6 

Estamos utilizando ASP.NET MVC y (naturalmente) enrutamiento ASP.NET.

El problema

El problema es que nuestros parámetros son dynamics, y (en teoría) no hay límite para la cantidad de parámetros que tenemos que acomodar.

Todo está bien hasta que fuimos golpeados por el siguiente tren:

HTTP Error 400.0 – Solicitud incorrecta ASP.NET detectó caracteres no válidos en la URL.

IIS arrojaría este error cuando nuestra URL haya pasado una cierta longitud.

The Nitty Gritty

Esto es lo que descubrimos:

Esto no es un problema de IIS

IIS tiene un límite máximo de longitud de ruta, pero el error anterior no es este.

Aprender punto iis dot net Cómo utilizar la sección de filtrado de solicitudes “Filtro basado en límites de solicitud”

Si el camino fuera demasiado largo para IIS, arrojaría un 404.14, no un 400.0.

Además, la longitud máxima de la ruta de acceso (y de la consulta) de IIS es configurable:

  

Este es un problema de ASP.NET

Después de hurgar un poco:

Enrutamiento de foros de IIS: longitud de URL máxima de ASP.NET 2.0? http://forums.iis.net/t/1105360.aspx

resulta que este es un problema de ASP.NET (bueno, realmente .NET).

El meollo del asunto es que, por lo que puedo decir, ASP.NET no puede manejar rutas de más de 260 caracteres.

El clavo en el ataúd en el que esto es confirmado por Phil the Haack mismo:

Stack Overflow ASP.NET url MAX_PATH límite ID de pregunta 265251

La pregunta

Entonces, ¿cuál es la pregunta?

La pregunta es, ¿cuán grande de una limitación es esto?

Para mi aplicación, es un asesino de oferta. Para la mayoría de las aplicaciones, probablemente no sea un problema.

¿Qué hay de la divulgación? En ningún lugar donde se menciona el enrutamiento ASP.NET, he oído alguna vez sobre esta limitación. El hecho de que ASP.NET MVC utiliza el enrutamiento ASP.NET hace que el impacto de esto sea aún mayor.

¿Qué piensas?

Terminé usando lo siguiente en el archivo web.config para resolver este problema usando Mvc2 y .Net Framework 4.0

  

Para resolver esto, haz esto:

En la raíz web.config para su proyecto, debajo del nodo system.web:

   ... 

Además, tuve que agregar esto en el nodo system.webServer o recibí un error de seguridad para mis cadenas de consulta largas:

       ... 

El servicio Http.sys está codificado con un máximo predeterminado de 260 caracteres por segmento Url.

Un “segmento Url” en este contexto es el contenido entre los caracteres “/” en la URL. Por ejemplo:

 http://www.example.com/segment-one/segment-two/segment-three 

La longitud máxima permitida del segmento Url se puede cambiar con la configuración del registro:

  • Clave: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
  • Valor: UrlSegmentMaxLength
  • Tipo: REG_DWORD
  • Datos: (Su nueva longitud máxima permitida del segmento Url deseada, por ejemplo, 4096)

Obtenga más información acerca de la configuración http.sys: http://support.microsoft.com/kb/820129

El valor máximo permitido es 32766. Si se especifica un valor mayor, se ignorará. (Crédito: Juan Mendes)

Es necesario reiniciar la PC para que un cambio en esta configuración tenga efecto. (Crédito: David Rettenbacher, Juan Mendes)

OK, así que parte de la razón por la que publiqué esto también fue porque hemos encontrado una solución alternativa.

Espero que esto sea útil para alguien en el futuro: D

La solución

La solución es bastante simple, y también es bastante agradable.

Como sabemos qué partes del sitio necesitarán usar parámetros dynamics (y, por lo tanto, tendrán una ruta y una longitud dinámicas), podemos evitar enviar esta url larga al enrutamiento ASP.NET interceptándola incluso antes de que llegue a ASP.NET.

Ingrese la reescritura de la URL de IIS7 (o cualquier módulo de reescritura equivalente).

Establecemos una regla como esta:

           

Básicamente, lo que estamos haciendo es mantener suficiente de la ruta para poder llamar a la ruta correcta en sentido descendente. El rest de la ruta URL que estamos pirateando.

¿A dónde va el rest de la URL?

Bueno, cuando se dispara una regla de reescritura, el módulo de reescritura de URL de IIS7 configura automágicamente este encabezado en la solicitud:

 HTTP_X_ORIGINAL_URL 

Downstream, en la parte de la aplicación que analiza la ruta dinámica, en lugar de mirar la ruta:

 HttpContext.Request.Url.PathAndQuery 

vemos ese encabezado en su lugar:

 HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"] 

Problema resuelto … ¡casi!

Los enganches

Accediendo al encabezado

En caso de que necesite saber, para acceder al encabezado del módulo de reescritura IIS7, puede hacerlo de dos maneras:

 HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"] 

o

 HttpContext.Request.Headers["X-ORIGINAL-URL"] 

Reparar rutas relativas

Lo que también notará es que, con la configuración anterior, se rompen todas las rutas relativas (URL que se definieron con un “~”).

Esto incluye las URL definidas con los métodos ASP.NET MVC HtmlHelper y UrlHelper (como Url.Route("Bla") ).

Aquí es donde el acceso al código ASP.NET MVC es increíble.

En el método System.Web.Mvc.PathHelper.GenerateClientUrlInternal() , se realiza una comprobación para ver si existe el mismo encabezado del módulo Rewrite de URL (ver arriba):

 // we only want to manipulate the path if URL rewriting is active, else we risk breaking the generated URL NameValueCollection serverVars = httpContext.Request.ServerVariables; bool urlRewriterIsEnabled = (serverVars != null && serverVars[_urlRewriterServerVar] != null); if (!urlRewriterIsEnabled) { return contentPath; } 

Si lo hace, se realiza un trabajo para preservar la URL de origen.

En nuestro caso, dado que no estamos utilizando la reescritura de URL de la manera “normal”, queremos cortocircuitar este proceso.

Queremos pretender que no se produjo ninguna reescritura de URL, ya que no queremos que se consideren las rutas relativas en el contexto de la URL original.

El truco más simple que pude pensar fue eliminar completamente esa variable de servidor, por lo que ASP.NET MVC no lo encontraría:

 protected void Application_BeginRequest() { string iis7UrlRewriteServerVariable = "HTTP_X_ORIGINAL_URL"; string headerValue = Request.ServerVariables[iis7UrlRewriteServerVariable]; if (String.IsNullOrEmpty(headerValue) == false) { Request.ServerVariables.Remove(iis7UrlRewriteServerVariable); Context.Items.Add(iis7UrlRewriteServerVariable, headerValue); } } 

(Tenga en cuenta que, en el método anterior, estoy eliminando el encabezado de Request.ServerVariables pero aún lo Context.Items en Context.Items . La razón para esto es que necesito acceder al valor del encabezado más adelante en el request pipe .)

¡Espero que esto ayude!

Creo que estás tratando de usar GET. Intente cambiar el método de solicitud a POST y ponga esos parámetros de cadena de consulta en el cuerpo de la solicitud.

La URL larga tampoco ayuda a SEO, ¿o sí?

Parece que la longitud máxima de la URL codificada se ha corregido en .NET 4.0 . En particular, ahora hay una sección web.config con:

  

que te permiten expandir el rango de URL permitidas.

Estaba teniendo un problema de longitud de URL máximo similar utilizando ASP.NET Web API 4, que generó un error ligeramente diferente:

error 404

La solución para mí se describió anteriormente al actualizar Web.config con AMBAS de las siguientes tags:

   

y