Capturando “Comprimento máximo da solicitação excedido”


112

Estou escrevendo uma função de upload e tenho problemas para capturar "System.Web.HttpException: Comprimento máximo da solicitação excedido" com arquivos maiores do que o tamanho máximo especificado httpRuntimeem web.config (tamanho máximo definido como 5120). Estou usando um simples <input>para o arquivo.

O problema é que a exceção é lançada antes do evento de clique do botão de upload e a exceção ocorre antes de meu código ser executado. Então, como faço para capturar e tratar a exceção?

EDIT: A exceção é lançada instantaneamente, então tenho certeza que não é um problema de tempo limite devido a conexões lentas.


5
Alguém tentou fazer isso com MVC? Parece que consigo capturar a exceção da maneira certa, mas não consigo pará-la: toda vez que tento renderizar uma página de erro, ocorre a mesma exceção.
Andy

Essa mensagem de erro é lançada pelo IIS antes de chegar ao controlador. Para notificar o usuário de que o arquivo excede o limite máximo de upload (definido em sua configuração da web), você pode validar diretamente o tamanho do arquivo via JS com um evento onchange. Por exemplo , <input type="file" id="upload" name="upload" onchange="showFileSize();" />Inside showFileSize(), você pode exibir uma mensagem de erro com base no tamanho do arquivo via var input = document.getElementById("upload"); var file = input.files[0];e anexar uma tag html.
Alfred Wallace

Respostas:


97

Infelizmente, não há maneira fácil de detectar essa exceção. O que faço é substituir o método OnError no nível da página ou o Application_Error em global.asax e, em seguida, verificar se foi uma falha de solicitação máxima e, em caso afirmativo, transferir para uma página de erro.

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

É um hack, mas o código abaixo funciona para mim

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

2
Obrigado. OnError não funcionou, mas Application_Error sim. Na verdade, temos um manipulador para isso, mas alguém o desativou no código.
Marcus L

até dois anos atrás, mas ainda quero perguntar se isso funcionou bem até agora. a comparação de strings de 'GetEntireRawContent' funciona bem? Não acho que seja um problema de tempo limite. há alguém se destacando por me apontar para algum lugar sem nuvens sobre isso?
Elaine

@Elaine sim, essa técnica ainda funciona com ASP.Net 4.0. Se você tentar fazer upload de uma solicitação maior que o comprimento máximo da solicitação, o ASP.Net lançará uma HttpException com o código de tempo limite. Dê uma olhada em System.Web.HttpRequest.GetEntireRawContent () usando refletor.
Damien McGivern

12
@ sam-rueby Não queria responder a uma mensagem de erro de string que pode mudar devido à localização.
Damien McGivern

4
Para .NET 4.0 e posterior, há uma maneira melhor de identificar se o tamanho máximo da solicitação foi excedido. Você pode verificar esta condição para HttpException: httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge- usando System.Web.Management.WebEventCodes
mco

58

Como o GateKiller disse, você precisa alterar o maxRequestLength. Você também pode precisar alterar o executionTimeout caso a velocidade de upload seja muito lenta. Observe que você não deseja que nenhuma dessas configurações seja muito grande, caso contrário, você estará aberto a ataques DOS.

O padrão para executionTimeout é 360 segundos ou 6 minutos.

Você pode alterar maxRequestLength e executeTimeout com o elemento httpRuntime .

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

EDITAR:

Se você quiser tratar a exceção independentemente, como já foi dito, você precisará tratá-la em Global.asax. Aqui está um link para um exemplo de código .


2
Obrigado pela sua resposta, mas como eu disse no meu comentário à resposta do GK isso realmente não resolve o meu problema. Também não é um problema de tempo limite, pois a exceção é lançada instantaneamente. Vou editar a pergunta para deixar isso mais claro.
Marcus L

4
O exemplo de código url aponta para uma página que não está disponível ... alguém pode corrigir isso?
deostroll de

20

Você pode resolver isso aumentando o comprimento máximo da solicitação em seu web.config:

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

O exemplo acima é para um limite de 100 Mb.


18
Sim e não. Você empurra o limite ainda mais, mas ele realmente não lida com a exceção. Você ainda terá o mesmo problema se alguém tentar fazer upload de 101+ Mb. O limite realmente precisa ser de 5 Mb.
Marcus L de

10

Se você também deseja uma validação do lado do cliente, para que haja menos necessidade de lançar exceções, você pode tentar implementar a validação do tamanho do arquivo do lado do cliente.

Nota: Isso só funciona em navegadores que suportam 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>


9

Olá, solução mencionada por Damien McGivern, Funciona apenas no IIS6,

Não funciona no IIS7 e no ASP.NET Development Server. Recebo a página exibindo "404 - Arquivo ou diretório não encontrado."

Alguma ideia?

EDITAR:

Entendi ... Essa solução ainda não funciona no ASP.NET Development Server, mas entendi o motivo pelo qual ela não estava funcionando no IIS7 no meu caso.

A razão é que o IIS7 tem uma varredura de solicitação embutida que impõe um limite de arquivo de upload que é padronizado para 30000000 bytes (que é um pouco menos que 30 MB).

E eu estava tentando fazer upload de um arquivo de tamanho 100 MB para testar a solução mencionada por Damien McGivern (com maxRequestLength = "10240" ou seja, 10 MB em web.config). Agora, se eu carregar o arquivo de tamanho> 10 MB e <30 MB, a página será redirecionada para a página de erro especificada. Mas se o tamanho do arquivo for> 30 MB, ele mostra a página de erro embutida feia exibindo "404 - Arquivo ou diretório não encontrado."

Portanto, para evitar isso, você deve aumentar o máximo. permitido comprimento de conteúdo de solicitação para seu site no IIS7. Isso pode ser feito usando o seguinte comando,

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

Eu defini o máximo comprimento do conteúdo de 200 MB.

Depois de fazer essa configuração, a página é redirecionada com sucesso para minha página de erro quando tento fazer upload de um arquivo de 100 MB

Consulte http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx para obter mais detalhes.


Desculpe! Eu adicionei minha consulta como uma resposta, não sei como adicionar comentários a postagens existentes.
Vinod T. Patil

1
Você só precisa de mais repetição. para comentar postagens. Consulte o faq para obter mais detalhes sobre o que você pode / não pode fazer com seu representante atual.
alegre

7

Esta é uma maneira alternativa, que não envolve nenhum "hacks", mas requer ASP.NET 4.0 ou posterior:

//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
    }
}

4

Uma maneira de fazer isso é definir o tamanho máximo em web.config como já foi declarado acima, por exemplo

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

então, quando você manipular o evento de upload, verifique o tamanho e se for superior a uma quantidade específica, você pode prendê-lo, por exemplo

protected void btnUploadImage_OnClick(object sender, EventArgs e)
{
    if (fil.FileBytes.Length > 51200)
    {
         TextBoxMsg.Text = "file size must be less than 50KB";
    }
}

1
Isso não funciona. O evento de clique nunca é acionado. A exceção acontece antes.
Lombas


3

No IIS 7 e além:

arquivo web.config:

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

Você pode então fazer o check-in do código, assim:

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

Apenas certifique-se de que o [Tamanho em bytes] no web.config seja maior do que o tamanho do arquivo que você deseja enviar, então você não receberá o erro 404. Você pode então verificar o tamanho do arquivo no código por trás usando ContentLength, que seria muito melhor


2

Como você provavelmente sabe, o comprimento máximo da solicitação é configurado em DOIS lugares.

  1. maxRequestLength - controlado no nível do aplicativo ASP.NET
  2. maxAllowedContentLength- sob <system.webServer>, controlado no nível do IIS

O primeiro caso é coberto por outras respostas a esta pergunta.

Para capturar o SEGUNDO, você precisa fazer isso em 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();
    }
}

1

Depois da etiqueta

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

adicione a seguinte tag

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

você pode adicionar o Url à página de erro ...


0

Você pode resolver isso aumentando a duração máxima da solicitação e o tempo limite de execução em seu web.config:

-Por favor, esclareça o tempo máximo de execução, ralador então 1200

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

0

Que tal pegá-lo no evento 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);
        }
    }

0

Pode ser verificado via:

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

                return;

            }
        }
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.