web-dev-qa-db-fra.com

ASP.NET MVC, Routage d'URL: longueur maximale du chemin d'accès (URL)

Le scénario

J'ai une application où nous avons pris la bonne vieille structure d'URL de chaîne de requête:

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

et l'a changé en une structure de chemin:

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

Nous utilisons ASP.NET MVC et (naturellement) le routage ASP.NET.

Le problème

Le problème est que nos paramètres sont dynamiques et qu’il n’ya (théoriquement) aucune limite à la quantité de paramètres à prendre en compte.

Tout va bien jusqu'à ce que nous soyons touchés par le train suivant:

Erreur HTTP 400.0 - Requête incorrecte ASP.NET a détecté des caractères non valides dans l'URL.

IIS lançait cette erreur lorsque notre URL avait dépassé une certaine longueur.

La Nitty Gritty

Voici ce que nous avons découvert:

Ce n'est pas un problème IIS

IIS a une limite de longueur de chemin maximale, mais l'erreur ci-dessus n'est pas ceci.

Apprendre dot iis dot net Comment utiliser le filtrage des demandes .__ Section "Filtre basé sur les limites des demandes"

Si le chemin était trop long pour IIS, il lancerait un 404.14 et non un 400.0.

De plus, la longueur maximale du chemin IIS (et de la requête) est configurable:

<requestLimits


   maxAllowedContentLength="30000000"


   maxUrl="260"


   maxQueryString="25" 


              />

Ceci est un problème ASP.NET

Après quelques plaisanteries:

Forums IIS Discussion: longueur maximale de l’URL pour ASP.NET 2.0? http://forums.iis.net/t/1105360.aspx

il s’avère que c’est un problème ASP.NET (enfin, .NET vraiment).

Le cœur du problème est que, autant que je sache, ASP.NET ne peut pas gérer de chemins d'accès de plus de 260 caractères.

Le clou dans le cercueil est que ceci est confirmé par Phil le Haack lui-même:

Stack OverflowASP.NET url MAX_PATH limit Question ID 265251

La question

Alors quelle est la question?

La question est, quelle est la taille de cette limitation?

Pour mon application, c'est un tueur d'affaire. Pour la plupart des applications, il s'agit probablement d'un non-problème.

Qu'en est-il de la divulgation? Nulle part où le routage ASP.NET est mentionné, n’ai-je jamais entendu parler de cette limitation. Le fait qu'ASP.NET MVC utilise le routage ASP.NET augmente encore l'impact de cette opération.

Qu'est-ce que tu penses?

59
Martin Suchanek

J'ai fini par utiliser les éléments suivants dans le fichier Web.config pour résoudre ce problème à l'aide de Mvc2 et de .Net Framework 4.0 

<httpRuntime maxUrlLength="1000" relaxedUrlToFileSystemMapping="true" />
46
lmingle

Le service Http.sys est codé avec un maximum par défaut de 260 caractères par segment d'URL.

Un "segment d'URL" dans ce contexte est le contenu entre les caractères "/" de l'URL. Par exemple:

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

La longueur maximale autorisée du segment d’URL peut être modifiée avec les paramètres de registre:

  • Clé: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\HTTP\Parameters
  • Valeur: UrlSegmentMaxLength
  • Type: REG_DWORD
  • Données: (longueur maximale autorisée de votre nouveau segment d’URL, par exemple 4096)

En savoir plus sur les paramètres http.sys: http://support.Microsoft.com/kb/820129

La valeur maximale autorisée est 32766. Si une valeur plus grande est spécifiée, elle sera ignorée. (Crédit: Juan Mendes)

Le redémarrage du PC est nécessaire pour que la modification de ce paramètre prenne effet. (Crédit: David Rettenbacher, Juan Mendes)

27
David Richoz

Pour résoudre ceci, procédez comme suit:

Dans la racine web.config de votre projet, sous le nœud system.web:

<system.web>
    <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />
...

De plus, j'ai dû ajouter ceci sous le nœud system.webServer ou j'ai eu une erreur de sécurité pour mes longues chaînes de requête:

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxUrl="10999" maxQueryString="2097151" />
      </requestFiltering>
    </security>
...
26
theJerm

OK, donc une partie de la raison pour laquelle j'ai posté cela était aussi parce que nous avons trouvé un travail autour.

J'espère que cela sera utile à quelqu'un dans le futur: D

La solution de contournement

La solution de contournement est assez simple et assez agréable aussi.

Puisque nous savons quelles parties du site devront utiliser des paramètres dynamiques (et auront donc un chemin et une longueur dynamiques), nous pouvons éviter d'envoyer cette URL longue à un routage ASP.NET en l'interceptant avant même qu'elle ne frappe ASP.NET.

Entrez IIS7 Url Rewriting (ou tout module de réécriture équivalent).

Nous établissons une règle comme celle-ci:

    <rewrite>
        <rules>
            <rule>
                <rule name="Remove Category Request Parameters From Url">
                <match url="^category/(\d+)/{0,1}(.*)$" />
                <action type="Rewrite" url="category/{R:1}" />
            </rule>
        </rules>
    </rewrite>

Fondamentalement, nous ne faisons que garder suffisamment de chemin pour pouvoir appeler le bon itinéraire en aval. Le reste du chemin de l'URL est en train d'être piraté.

Où va le reste de l'URL?

Eh bien, quand une règle de réécriture est déclenchée, le module IIS7 URL Rewrite définit automatiquement cet en-tête dans la requête:

HTTP_X_ORIGINAL_URL

En aval, dans la partie de l'application qui analyse le chemin dynamique, au lieu de regarder le chemin:

HttpContext.Request.Url.PathAndQuery

nous regardons plutôt cet en-tête:

HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

Problème résolu ... presque!

Les chicots

Accéder à l'en-tête

Si vous avez besoin de savoir, pour accéder à l'en-tête du module IIS7 Rewrite, vous pouvez le faire de deux manières:

HttpContext.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

ou

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

Correction des chemins relatifs

Vous remarquerez également que, avec la configuration ci-dessus, tous les chemins relatifs sont rompus (les URL définies avec un "~").

Cela inclut les URL définies avec les méthodes ASP.NET MVC HtmlHelper et UrlHelper (telles que Url.Route("Bla")).

C'est ici que l'accès au code ASP.NET MVC est génial.

Dans la méthode System.Web.Mvc.PathHelper.GenerateClientUrlInternal(), on vérifie si le même en-tête de module de réécriture d'URL existe (voir ci-dessus):

// 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 tel est le cas, un travail est fait pour préserver l'URL d'origine. 

Dans notre cas, comme nous n'utilisons pas la réécriture d'URL de manière "normale", nous voulons court-circuiter ce processus.

Nous voulons prétendre qu'aucune réécriture d'URL n'a eu lieu, car nous ne voulons pas que les chemins relatifs soient pris en compte dans le contexte de l'URL d'origine.

Le hack le plus simple auquel je pouvais penser était de supprimer complètement cette variable de serveur afin qu'ASP.NET MVC ne la trouve pas:

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

(Notez que, dans la méthode ci-dessus, je supprime l'en-tête de Request.ServerVariables tout en le conservant dans Context.Items. La raison en est que j'ai besoin d'accéder à la valeur de l'en-tête plus tard dans le canal de demande.)

J'espère que cela t'aides!

14
Martin Suchanek

Je pense que vous essayez très fort d'utiliser GET. Essayez de changer la méthode de requête en POST et de placer ces paramètres de chaîne de requête dans le corps de la requête.

Une longue URL ne facilite pas le référencement, n'est-ce pas?

2
Adrian Godong

Il semble que la longueur maximale de l'URL codée en dur ait été corrigée dans .NET 4.0 . En particulier, il existe maintenant une section web.config avec:

<httpRuntime maxRequestPathLength="260" maxQueryStringLength="2048" /> 

qui vous permettent d’élargir la plage des URL autorisées.

1
Joannes Vermorel

J'avais un problème similaire de longueur maximale d'URL avec ASP.NET Web API 4, qui générait une erreur légèrement différente: 

Erreur 404

Le correctif pour moi a été décrit ci-dessus en mettant à jour le fichier Web.config avec les balises suivantes:

<system.web>
    <httpRuntime maxUrlLength="10999" maxQueryStringLength="2097151" />

et

<system.webServer>
    <security>
      <requestFiltering>
        <requestLimits maxUrl="10999" maxQueryString="2097151" />
      </requestFiltering>
    </security>
0
J. Ventry