Capture "Longueur maximale de la demande dépassée"

112

J'écris une fonction de téléchargement et j'ai des problèmes pour attraper "System.Web.HttpException: la longueur maximale de la demande est dépassée" avec des fichiers plus grands que la taille maximale spécifiée httpRuntimedans web.config (taille maximale définie sur 5120). J'utilise un simple <input>pour le fichier.

Le problème est que l'exception est levée avant l'événement de clic du bouton de téléchargement, et l'exception se produit avant l'exécution de mon code. Alors, comment attraper et gérer l'exception?

EDIT: l'exception est lancée instantanément, donc je suis presque sûr que ce n'est pas un problème de délai d'attente en raison de connexions lentes.

Marcus L
la source
5
Quelqu'un a-t-il essayé cela avec MVC? Il semble que je puisse attraper l'exception de la bonne manière, mais je ne peux pas l'arrêter: chaque fois que j'essaye de rendre une page d'erreur, la même exception se produit.
Andy
Ce message d'erreur est généré par IIS avant d'atteindre le contrôleur. Pour informer l'utilisateur que le fichier dépasse la limite de téléchargement maximale (définie dans votre configuration Web), vous pouvez directement valider la taille du fichier via JS avec un événement onchange. Pour par exemple <input type="file" id="upload" name="upload" onchange="showFileSize();" />Inside showFileSize(), vous pouvez afficher un message d'erreur basé sur la taille de votre fichier via var input = document.getElementById("upload"); var file = input.files[0];et ajouter une balise html.
Alfred Wallace

Réponses:

97

Il n'y a malheureusement pas de moyen facile d'attraper une telle exception. Ce que je fais est de remplacer la méthode OnError au niveau de la page ou Application_Error dans global.asax, puis de vérifier s'il s'agissait d'un échec de Max Request et, le cas échéant, de transférer vers une page d'erreur.

protected override void OnError(EventArgs e) .....


private void Application_Error(object sender, EventArgs e)
{
    if (GlobalHelper.IsMaxRequestExceededException(this.Server.GetLastError()))
    {
        this.Server.ClearError();
        this.Server.Transfer("~/error/UploadTooLarge.aspx");
    }
}

C'est un hack mais le code ci-dessous fonctionne pour moi

const int TimedOutExceptionCode = -2147467259;
public static bool IsMaxRequestExceededException(Exception e)
{
    // unhandled errors = caught at global.ascx level
    // http exception = caught at page level

    Exception main;
    var unhandled = e as HttpUnhandledException;

    if (unhandled != null && unhandled.ErrorCode == TimedOutExceptionCode)
    {
        main = unhandled.InnerException;
    }
    else
    {
        main = e;
    }


    var http = main as HttpException;

    if (http != null && http.ErrorCode == TimedOutExceptionCode)
    {
        // hack: no real method of identifying if the error is max request exceeded as 
        // it is treated as a timeout exception
        if (http.StackTrace.Contains("GetEntireRawContent"))
        {
            // MAX REQUEST HAS BEEN EXCEEDED
            return true;
        }
    }

    return false;
}
Damien McGivern
la source
2
Merci. OnError n'a pas fonctionné, mais Application_Error l'a fait. Nous avons en fait un gestionnaire pour cela, mais quelqu'un l'avait désactivé dans le code.
Marcus L
il y a encore deux ans, mais je veux toujours demander si cela a bien fonctionné jusqu'à présent? la comparaison de chaînes de «GetEntireRawContent» fonctionne-t-elle correctement? Je ne pense pas que ce soit un problème de délai d'attente. y a-t-il quelqu'un qui se démarque pour m'avoir signalé quelque part quelque part à ce sujet?
Elaine
@Elaine ouais cette technique fonctionne toujours avec ASP.Net 4.0. Si vous essayez de télécharger une demande qui est supérieure à la longueur de demande maximale, ASP.Net lève une HttpException avec le code de délai. Jetez un œil à System.Web.HttpRequest.GetEntireRawContent () à l'aide de reflector.
Damien McGivern
12
@ sam-rueby Je ne voulais pas répondre à un message d'erreur de chaîne qui pourrait changer en raison de la localisation.
Damien McGivern
4
Pour .NET 4.0 et versions ultérieures, il existe un meilleur moyen d'identifier si la taille maximale de la demande a été dépassée. Vous pouvez vérifier cette condition pour HttpException: httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge- en utilisant System.Web.Management.WebEventCodes
mco
58

Comme GateKiller l'a dit, vous devez changer le maxRequestLength. Vous devrez peut-être également modifier le executionTimeout au cas où la vitesse de téléchargement serait trop lente. Notez que vous ne voulez pas que l'un de ces paramètres soit trop gros, sinon vous serez ouvert aux attaques DOS.

La valeur par défaut pour executionTimeout est de 360 ​​secondes ou 6 minutes.

Vous pouvez modifier maxRequestLength et executionTimeout avec l' élément httpRuntime .

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <httpRuntime maxRequestLength="102400" executionTimeout="1200" />
    </system.web>
</configuration>

ÉDITER:

Si vous souhaitez gérer l'exception malgré tout, comme cela a déjà été indiqué, vous devrez la gérer dans Global.asax. Voici un lien vers un exemple de code .

Jonathan Parker
la source
2
Merci pour votre réponse, mais comme je l'ai dit dans mon commentaire à la réponse de GK, cela ne résout pas vraiment mon problème. Ce n'est pas non plus un problème de délai d'expiration, car l'exception est lancée instantanément. Je vais modifier la question pour que cela soit plus clair.
Marcus L
4
L'exemple de code URL pointe vers une page qui n'est pas disponible ... Quelqu'un peut-il résoudre ce problème?
deostroll
20

Vous pouvez résoudre ce problème en augmentant la longueur maximale de la requête dans votre web.config:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <httpRuntime maxRequestLength="102400" />
    </system.web>
</configuration>

L'exemple ci-dessus concerne une limite de 100 Mo.

GateKiller
la source
18
Oui et non. Vous repoussez la limite plus loin, mais cela ne gère pas vraiment l'exception. Vous aurez toujours le même problème si quelqu'un essaie de télécharger 101+ Mb. La limite doit vraiment être de 5 Mo.
Marcus L
10

Si vous souhaitez également une validation côté client afin de réduire le besoin de lever des exceptions, vous pouvez essayer d'implémenter la validation de la taille du fichier côté client.

Remarque: cela ne fonctionne que dans les navigateurs prenant en charge HTML5. http://www.html5rocks.com/en/tutorials/file/dndfiles/

<form id="FormID" action="post" name="FormID">
    <input id="target" name="target" class="target" type="file" />
</form>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js" type="text/javascript"></script>

<script type="text/javascript" language="javascript">

    $('.target').change(function () {

        if (typeof FileReader !== "undefined") {
            var size = document.getElementById('target').files[0].size;
            // check file size

            if (size > 100000) {

                $(this).val("");

            }
        }

    });

</script>

Andrew
la source
9

Salut solution mentionnée par Damien McGivern, fonctionne uniquement sur IIS6,

Il ne fonctionne pas sur IIS7 et ASP.NET Development Server. J'obtiens la page affichant "404 - Fichier ou répertoire non trouvé."

Des idées?

ÉDITER:

Compris ... Cette solution ne fonctionne toujours pas sur ASP.NET Development Server, mais j'ai eu la raison pour laquelle elle ne fonctionnait pas sur IIS7 dans mon cas.

La raison en est qu'IIS7 a une analyse des demandes intégrée qui impose un plafond de fichier de téléchargement qui est par défaut de 30000000 octets (ce qui est légèrement inférieur à 30 Mo).

Et j'essayais de télécharger un fichier de taille 100 Mo pour tester la solution mentionnée par Damien McGivern (avec maxRequestLength = "10240" soit 10 Mo dans web.config). Maintenant, si je télécharge le fichier de taille> 10 Mo et <30 Mo, la page est redirigée vers la page d'erreur spécifiée. Mais si la taille du fichier est> 30 Mo, la vilaine page d'erreur intégrée affiche «404 - Fichier ou répertoire introuvable».

Donc, pour éviter cela, vous devez augmenter le max. longueur de contenu de demande autorisée pour votre site Web dans IIS7. Cela peut être fait en utilisant la commande suivante,

appcmd set config "SiteName" -section:requestFiltering -requestLimits.maxAllowedContentLength:209715200 -commitpath:apphost

J'ai défini le max. longueur du contenu à 200 Mo.

Après avoir effectué ce paramètre, la page est redirigée avec succès vers ma page d'erreur lorsque j'essaye de télécharger un fichier de 100 Mo

Reportez-vous à http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx pour plus de détails.

Vinod T. Patil
la source
Désolé! J'ai ajouté ma requête en tant que réponse, je ne sais pas comment ajouter des commentaires aux messages existants.
Vinod T.Patil
1
Vous avez juste besoin de plus de représentants. pour commenter les messages. Consultez la FAQ pour plus de détails sur ce que vous pouvez / ne pouvez pas faire avec votre représentant actuel.
slaphappy
7

Voici une autre manière, qui n'implique aucun "hacks", mais nécessite ASP.NET 4.0 ou version ultérieure:

//Global.asax
private void Application_Error(object sender, EventArgs e)
{
    var ex = Server.GetLastError();
    var httpException = ex as HttpException ?? ex.InnerException as HttpException;
    if(httpException == null) return;

    if(httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge)
    {
        //handle the error
        Response.Write("Sorry, file is too big"); //show this message for instance
    }
}
Serge Shultz
la source
4

Une façon de faire est de définir la taille maximale dans web.config comme cela a déjà été indiqué ci-dessus, par exemple

<system.web>         
    <httpRuntime maxRequestLength="102400" />     
</system.web>

Ensuite, lorsque vous gérez l'événement de téléchargement, vérifiez la taille et si elle dépasse un montant spécifique, vous pouvez le piéger, par exemple

protected void btnUploadImage_OnClick(object sender, EventArgs e)
{
    if (fil.FileBytes.Length > 51200)
    {
         TextBoxMsg.Text = "file size must be less than 50KB";
    }
}
BaggieBoy
la source
1
Cela ne marche pas. L'événement de clic n'est jamais déclenché. L'exception se produit avant.
Lombas
3

Dans IIS 7 et au-delà:

Fichier web.config:

<system.webServer>
  <security >
    <requestFiltering>
      <requestLimits maxAllowedContentLength="[Size In Bytes]" />
    </requestFiltering>
  </security>
</system.webServer>

Vous pouvez ensuite enregistrer le code derrière, comme ceci:

If FileUpload1.PostedFile.ContentLength > 2097152 Then ' (2097152 = 2 Mb)
  ' Exceeded the 2 Mb limit
  ' Do something
End If

Assurez-vous simplement que la [Taille en octets] dans le web.config est supérieure à la taille du fichier que vous souhaitez télécharger, vous n'obtiendrez pas l'erreur 404. Vous pouvez ensuite vérifier la taille du fichier dans le code en utilisant le ContentLength qui serait bien meilleur

Walery Strauch
la source
2

Comme vous le savez probablement, la longueur maximale de la demande est configurée en DEUX endroits.

  1. maxRequestLength - contrôlé au niveau de l'application ASP.NET
  2. maxAllowedContentLength- sous <system.webServer>, contrôlé au niveau IIS

Le premier cas est couvert par d'autres réponses à cette question.

Pour attraper LE SECOND, vous devez le faire dans global.asax:

protected void Application_EndRequest(object sender, EventArgs e)
{
    //check for the "file is too big" exception if thrown at the IIS level
    if (Response.StatusCode == 404 && Response.SubStatusCode == 13)
    {
        Response.Write("Too big a file"); //just an example
        Response.End();
    }
}
jazzcat
la source
1

Après le tag

<security>
     <requestFiltering>
         <requestLimits maxAllowedContentLength="4500000" />
     </requestFiltering>
</security>

ajouter la balise suivante

 <httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="13" />
  <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="http://localhost/ErrorPage.aspx" responseMode="Redirect" />
</httpErrors>

vous pouvez ajouter l'URL à la page d'erreur ...

Diego
la source
0

Vous pouvez résoudre ce problème en augmentant la longueur maximale de la requête et le délai d'exécution dans votre web.config:

-Veuillez clarifier le délai d'exécution maximum de la râpe, puis 1200

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>
Nasurudeen
la source
0

Que diriez-vous de l'attraper à l'événement EndRequest?

protected void Application_EndRequest(object sender, EventArgs e)
    {
        HttpRequest request = HttpContext.Current.Request;
        HttpResponse response = HttpContext.Current.Response;
        if ((request.HttpMethod == "POST") &&
            (response.StatusCode == 404 && response.SubStatusCode == 13))
        {
            // Clear the response header but do not clear errors and
            // transfer back to requesting page to handle error
            response.ClearHeaders();
            HttpContext.Current.Server.Transfer(request.AppRelativeCurrentExecutionFilePath);
        }
    }
Khoa Tran
la source
0

Il peut être vérifié via:

        var httpException = ex as HttpException;
        if (httpException != null)
        {
            if (httpException.WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
            {
                // Request too large

                return;

            }
        }
Raghav
la source