2009-03-20 3 views
96

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

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

EDIT: Исключение бросается мгновенно, поэтому я уверен, что это не проблема таймаута из-за медленных соединений.

+5

ли кто-нибудь попробует это с MVC? Кажется, я могу правильно поймать исключение, но я не могу его остановить: каждый раз, когда я пытаюсь отобразить страницу с ошибкой, возникает одно и то же исключение. – Andy

ответ

88

Невозможно, к сожалению, получить такое исключение. То, что я делаю, либо переопределяет метод 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. У нас на самом деле есть обработчик для этого, но кто-то отключил его в коде. –

+0

еще два года назад, но я все еще хочу спросить, работает ли это до сих пор? действительно ли строковое сравнение «GetEntireRawContent» работает нормально? Я не думаю, что это проблема с тайм-аутом. есть ли кто-нибудь, кто стоит за то, чтобы указывать мне на что-нибудь, чтобы что-то сказать? – Elaine

+0

@ Элейн, эта техника все еще работает с ASP.Net 4.0. Если вы попытаетесь загрузить запрос, который больше максимальной длины запроса, ASP.Net выдает исключение HttpException с кодом таймаута. Посмотрите в System.Web.HttpRequest.GetEntireRawContent(), используя отражатель. –

18

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

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

В приведенном выше примере для предела 100Mb.

+17

Да, и нет. Вы продвигаете предел дальше, но на самом деле оно не справляется с исключением. У вас по-прежнему будет такая же проблема, если кто-то попытается загрузить 101+ Мб. Предел действительно должен быть 5 Мб. –

54

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

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

Вы можете изменить maxRequestLength и executeTimeout с помощью httpRuntime Element.

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

EDIT:

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

+2

Спасибо за ваш ответ, но, как я сказал в своем комментарии к ответу ГК, это не реально решает мою проблему. Это тоже не проблема с тайм-аутом, так как исключение бросается мгновенно. Я отредактирую вопрос, чтобы сделать это более ясным. –

+0

См. Мое редактирование для обработки ошибки в Global.asax –

+0

Yup, это сделал трюк. Благодаря! –

9

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

Это не работает на IIS7 и ASP. NET Development Server. Я получаю отображение страницы «404 - Файл или каталог не найдены».

Любые идеи?

EDIT:

Понял ... Это решение до сих пор не работает на 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 МБ.

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

см, http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx для более подробной информации.

+0

Извините! Я добавил свой запрос в качестве ответа, я не знаю, как добавлять комментарии к существующим сообщениям. –

+1

Вам просто нужно больше rep. комментировать сообщения. См. Faq для получения дополнительной информации о том, что вы можете/не можете сделать с вашим текущим представителем. – slaphappy

9

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

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

5

Один из способов сделать это, чтобы установить максимальный размер в 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"; 
    } 
} 
+0

Это не работает. Событие клика никогда не запускается. Исключение случается раньше. – Lombas

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 

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

0

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

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

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

Вот альтернативный способ, который не предполагает каких-либо «хаки», но требует 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 
    } 
} 
0

После тега

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

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

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

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

  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(); 
    } 
} 
Смежные вопросы