Сообщение «Превышена максимальная длина запроса»

112

Я пишу функцию загрузки, и у меня проблемы с обнаружением «System.Web.HttpException: максимальная длина запроса превышена» с файлами, размер которых превышает указанный максимальный размер httpRuntimeв web.config (максимальный размер установлен на 5120). Я использую простой <input>для файла.

Проблема в том, что исключение генерируется перед событием нажатия кнопки загрузки, а исключение происходит до запуска моего кода. Итак, как мне поймать и обработать исключение?

РЕДАКТИРОВАТЬ: исключение создается мгновенно, поэтому я почти уверен, что это не проблема тайм-аута из-за медленного соединения.

Маркус Л
источник
5
Кто-нибудь пробовал это с MVC? Кажется, я могу правильно поймать исключение, но я не могу его остановить: каждый раз, когда я пытаюсь отобразить страницу с ошибкой, возникает одно и то же исключение.
Энди
Это сообщение об ошибке выдается IIS до того, как оно достигнет контроллера. Чтобы уведомить пользователя о том, что файл превышает максимальный предел загрузки (установленный в вашей веб-конфигурации), вы можете напрямую проверить размер файла через JS с событием onchange. Например, для <input type="file" id="upload" name="upload" onchange="showFileSize();" />Inside showFileSize()вы можете отобразить сообщение об ошибке в зависимости от размера вашего файла с помощью var input = document.getElementById("upload"); var file = input.files[0];тега html и добавить его.
Альфред Уоллес

Ответы:

97

К сожалению, нет простого способа отловить такое исключение. Что я делаю, так это либо переопределяю метод OnError на уровне страницы, либо Application_Error в global.asax, затем проверяю, был ли сбой Max Request, и, если да, перехожу на страницу с ошибкой.

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

Это взлом, но приведенный ниже код мне подходит

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
Спасибо. OnError не работал, но Application_Error работал. У нас есть обработчик для этого, но кто-то отключил его в коде.
Marcus L,
даже два года назад, но я все еще хочу спросить, нормально ли это работало до сих пор? Хорошо ли работает сравнение строк GetEntireRawContent? Я не думаю, что это проблема с тайм-аутом. Есть ли кто-нибудь, кто указал мне на что-то необлачное по этому поводу?
Элейн
@Elaine, да, этот метод все еще работает с ASP.Net 4.0. Если вы пытаетесь загрузить запрос, превышающий максимальную длину запроса, ASP.Net генерирует исключение HttpException с кодом тайм-аута. Посмотрите System.Web.HttpRequest.GetEntireRawContent () с помощью отражателя.
Дэмиен МакГиверн
12
@ sam-rueby Я не хотел отвечать на сообщение об ошибке строки, которое могло измениться из-за локализации.
Дэмиен МакГиверн,
4
Для .NET 4.0 и более поздних версий есть лучший способ определить, превышен ли максимальный размер запроса. Вы можете проверить это условие для HttpException: httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge- используя System.Web.Management.WebEventCodes
mco
58

Как сказал GateKiller, вам нужно изменить maxRequestLength. Вам также может потребоваться изменить executionTimeout, если скорость загрузки слишком низкая. Обратите внимание, что вы не хотите, чтобы ни одна из этих настроек была слишком большой, иначе вы будете уязвимы для атак DOS.

По умолчанию для executionTimeout 360 секунд или 6 минут.

Вы можете изменить maxRequestLength и executionTimeout с помощью элемента httpRuntime .

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

РЕДАКТИРОВАТЬ:

Если вы хотите обработать исключение независимо от того, как уже было сказано, вам нужно будет обработать его в Global.asax. Вот ссылка на пример кода .

Джонатан Паркер
источник
2
Спасибо за ответ, но, как я сказал в своем комментарии к ответу GK, это на самом деле не решает мою проблему. Это также не проблема тайм-аута, поскольку исключение создается мгновенно. Я отредактирую вопрос, чтобы было понятнее.
Marcus L,
4
URL-адрес примера кода указывает на страницу, которая недоступна ... может ли кто-нибудь исправить это?
Деостролл
20

Вы можете решить эту проблему, увеличив максимальную длину запроса в вашем web.config:

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

В приведенном выше примере используется ограничение в 100 МБ.

GateKiller
источник
18
Да и нет. Вы увеличиваете предел, но на самом деле это не обрабатывает исключение. У вас все равно будет та же проблема, если кто-то попытается загрузить более 101 Мб. Лимит действительно должен быть 5 Мб.
Marcus L,
10

Если вам также нужна проверка на стороне клиента, чтобы у вас не возникало необходимости генерировать исключения, вы можете попытаться реализовать проверку размера файла на стороне клиента.

Примечание. Это работает только в браузерах, поддерживающих 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

Привет, решение, упомянутое Дэмиеном МакГиверном, работает только на IIS6,

Он не работает на IIS7 и сервере разработки ASP.NET. Я получаю страницу с сообщением «404 - файл или каталог не найден».

Любые идеи?

РЕДАКТИРОВАТЬ:

Понятно ... Это решение по-прежнему не работает на сервере разработки ASP.NET, но я понял причину, по которой в моем случае оно не работало на IIS7.

Причина в том, что IIS7 имеет встроенное сканирование запросов, которое накладывает ограничение на загружаемый файл, которое по умолчанию составляет 30000000 байт (что немного меньше 30 МБ).

И я пытался загрузить файл размером 100 МБ, чтобы протестировать решение, упомянутое Дэмиеном МакГиверном (с maxRequestLength = "10240", то есть 10 МБ в web.config). Теперь, если я загружу файл размером> 10 МБ и <30 МБ, тогда страница будет перенаправлена ​​на указанную страницу ошибки. Но если размер файла> 30 МБ, то отображается уродливая встроенная страница ошибки с отображением «404 - файл или каталог не найден».

Итак, чтобы этого избежать, вам нужно увеличить макс. допустимая длина содержимого запроса для вашего веб-сайта в IIS7. Это можно сделать с помощью следующей команды,

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

Я установил макс. длина содержимого до 200 МБ.

После выполнения этой настройки страница успешно перенаправляется на мою страницу с ошибкой, когда я пытаюсь загрузить файл размером 100 МБ.

См. Http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx для получения дополнительных сведений.

Винод Т. Патил
источник
Сожалею! Я добавил свой запрос в качестве ответа, я не знаю, как добавлять комментарии к существующим сообщениям.
Винод Т. Патил
1
Тебе просто нужно больше повторений. комментировать посты. Смотрите часто задаваемые вопросы, чтобы узнать больше о том, что вы можете / не можете делать со своим текущим представителем.
slaphappy
7

Вот альтернативный способ, который не требует «взломов», но требует ASP.NET 4.0 или более поздней версии:

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

Один из способов сделать это - установить максимальный размер в web.config, как уже было сказано выше, например

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

затем, когда вы обрабатываете событие загрузки, проверьте размер, и если он превышает определенную сумму, вы можете поймать его, например

protected void btnUploadImage_OnClick(object sender, EventArgs e)
{
    if (fil.FileBytes.Length > 51200)
    {
         TextBoxMsg.Text = "file size must be less than 50KB";
    }
}
BaggieBoy
источник
1
Это не работает. Событие щелчка никогда не запускается. Исключение случается раньше.
Ломбас
3

В IIS 7 и выше:

файл web.config:

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

Затем вы можете проверить код позади, например:

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

Просто убедитесь, что [Размер в байтах] в web.config больше, чем размер файла, который вы хотите загрузить, тогда вы не получите ошибку 404. Затем вы можете проверить размер файла в коде позади, используя ContentLength, что было бы намного лучше

Валери Штраух
источник
2

Как вы, наверное, знаете, максимальная длина запроса настраивается в ДВУХ местах.

  1. maxRequestLength - контролируется на уровне приложения ASP.NET
  2. maxAllowedContentLength- под <system.webServer>, контролируется на уровне IIS

К первому случаю относятся и другие ответы на этот вопрос.

Чтобы поймать ВТОРОЙ, вам нужно сделать это в 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
источник
1

После тега

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

добавить следующий тег

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

вы можете добавить URL-адрес на страницу с ошибкой ...

Диего
источник
0

Вы можете решить эту проблему, увеличив максимальную длину запроса и время выполнения в вашем web.config:

-Уточните, пожалуйста, максимальное время выполнения теркой, затем 1200

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>
Насурудин
источник
0

Как насчет того, чтобы поймать это на событии 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

Это можно проверить через:

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

                return;

            }
        }
Raghav
источник