Перехват "Превышена максимальная длина запроса"
Я пишу функцию загрузки, и у меня возникают проблемы с перехватом "System.Web.HttpException: превышена максимальная длина запроса" с файлами, размер которых превышает указанный максимальный размер в httpRuntime
в web.config (максимальный размер 5120). Я использую простую <input>
для файла.
Проблема в том, что исключение выдается до нажатия кнопки загрузки кнопки, а исключение происходит до запуска моего кода. Итак, как мне поймать и обработать исключение?
РЕДАКТИРОВАТЬ: Исключение выдается мгновенно, поэтому я уверен, что это не проблема тайм-аута из-за медленных соединений.
16 ответов
К сожалению, нет простого способа поймать такое исключение. То, что я делаю, это либо переопределяю метод 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;
}
Как сказал GateKiller, вам нужно изменить maxRequestLength. Вам также может понадобиться изменить executeTimeout, если скорость загрузки слишком низкая. Обратите внимание, что вы не хотите, чтобы какой-либо из этих параметров был слишком большим, иначе вы будете открыты для атак DOS.
Значение по умолчанию для executeTimeout составляет 360 секунд или 6 минут.
Вы можете изменить maxRequestLength и executeTimeout с помощью элемента httpRuntime.
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<httpRuntime maxRequestLength="102400" executionTimeout="1200" />
</system.web>
</configuration>
РЕДАКТИРОВАТЬ:
Если вы хотите обработать исключение независимо от того, как уже было сказано, вам нужно обработать его в Global.asax. Вот ссылка на пример кода.
Вы можете решить эту проблему, увеличив максимальную длину запроса в вашем файле web.config:
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<httpRuntime maxRequestLength="102400" />
</system.web>
</configuration>
Пример выше для предела 100 МБ.
Если вам нужна проверка на стороне клиента, и вам не нужно создавать исключения, вы можете попытаться реализовать проверку размера файла на стороне клиента.
Примечание: это работает только в браузерах, которые поддерживают 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>
Привет решение, упомянутое Дэмиеном МакГиверном, работает только на IIS6,
Он не работает на IIS7 и ASP.NET Development Server. Я получаю страницу, отображающую "404 - Файл или каталог не найден".
Есть идеи?
РЕДАКТИРОВАТЬ:
Понятно... Это решение до сих пор не работает на ASP.NET Development Server, но у меня есть причина, почему оно не работает на 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 для получения дополнительной информации.
Вот альтернативный способ, который не включает никаких "взломов", но требует 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
}
}
Один из способов сделать это - установить максимальный размер в файле 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";
}
}
Решение, которое работает с IIS7 и более поздними версиями: отображение настраиваемой страницы ошибок, когда загрузка файла превышает допустимый размер в ASP.NET MVC
В 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, который был бы намного лучше
Как вы, наверное, знаете, максимальная длина запроса настраивается в ДВУХ местах.
maxRequestLength
- контролируется на уровне приложения ASP.NETmaxAllowedContentLength
- под<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();
}
}
Я использую элемент управления FileUpload и клиентский скрипт для проверки размера файла.
HTML (обратите внимание на OnClientClick - выполняется до OnClick):
<asp:FileUpload ID="FileUploader" runat="server" />
<br />
<asp:Button ID="btnUpload" Text="Upload" runat="server" OnClientClick="return checkFileSize()" OnClick="UploadFile" />
<br />
<asp:Label ID="lblMessage" runat="server" CssClass="lblMessage"></asp:Label>
Затем сценарий (обратите внимание на "return false", если размер слишком велик: это отменяет OnClick):
function checkFileSize()
{
var input = document.getElementById("FileUploader");
var lbl = document.getElementById("lblMessage");
if (input.files[0].size < 4194304)
{
lbl.className = "lblMessage";
lbl.innerText = "File was uploaded";
}
else
{
lbl.className = "lblError";
lbl.innerText = "Your file cannot be uploaded because it is too big (4 MB max.)";
return false;
}
}
После тега
<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 на страницу ошибки...
Вы можете решить эту проблему, увеличив максимальную длину запроса и время выполнения в вашем файле web.config:
-Пожалуйста, уточните максимальное время выполнения терки, чем 1200
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>
Как насчет поймать его на мероприятии 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);
}
}
Следуя ответу Мартина ван Бергейка, я добавил дополнительный блок if, чтобы проверить, действительно ли они выбрали файл перед отправкой.
if(input.files[0] == null)
{lbl.innertext = "You must select a file before selecting Submit"}
return false;
Это можно проверить через:
var httpException = ex as HttpException;
if (httpException != null)
{
if (httpException.WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
{
// Request too large
return;
}
}