Где мне поймать и обработать превышение maxAllowedContentLength в IIS7? - PullRequest
13 голосов
/ 20 февраля 2009

У меня есть страница aspx, где я разрешаю пользователю загружать файл, и я хочу ограничить максимальный размер загрузки файла до 10 МБ. IIS7, .NET 3.5. В моем файле web.config настроено следующее:

<location path="foo.aspx">
    <system.web>
        <!-- maxRequestLength: kbytes, executionTimeout:seconds -->
        <httpRuntime maxRequestLength="10240" executionTimeout="120" />
        <authorization>
            <allow roles="customRole"/>
            <!-- Deny everyone else -->
            <deny users="*"/>
        </authorization>
    </system.web>
    <system.webServer>
        <security>
            <requestFiltering>
                <!-- maxAllowedContentLength: bytes -->
                <requestLimits maxAllowedContentLength="10240000"/>
            </requestFiltering>
        </security>
        <handlers accessPolicy="Read, Script">
            <add name="foo" path="foo.aspx" verb="POST"
               type="System.Web.UI.PageHandlerFactory"
               preCondition="integratedMode" />
        </handlers>       
    </system.webServer>
</location>

У меня есть пользовательский модуль обработки ошибок, который реализует IHttpModule. Я обнаружил, что когда maxRequestLength превышен, HttpApplication.Error действительно повышается. Однако когда я играю с maxAllowedContentLength, событие HttpApplication.Error не вызывается, и пользователь перенаправляется на страницу 404.13. Я подключился к Visual Studio с включенными исключениями первого шанса. Ничего не выбрасывается.

Моя первая мысль - проверить длину содержимого заголовка в более раннем событии - есть ли рекомендации / лучшие практики, где я это делаю? PostLogRequest? EndRequest

Ответы [ 2 ]

14 голосов
/ 21 февраля 2009

Посмотрев Обзор жизненного цикла приложений ASP.NET для IIS 7.0 и выполнив собственные эксперименты, я предполагаю, что проверка запросов выполняется IIS изнутри до возникновения какого-либо из событий.

Похоже, что только LogRequest, PostLogRequest, EndRequest, PreSendRequestContent и PreSendRequestHeaders вызываются после внутренней проверки с этой ошибкой.

Я решил присоединить обработчик события к событию HttpApplication.EndRequest в моем настраиваемом обработчике ошибок и проверить код состояния 404.13 на POST и обработать, как мне нужно, чтобы он обрабатывался, что в моем случае заключается в перенаправлении на вызывающая страница, которая проверит Server.GetLastError() и покажет конечную ошибку для пользователя.

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

Я бы приветствовал отзывы об этом подходе и альтернативах.

3 голосов
/ 15 апреля 2011

Самый простой способ - обработать его в методе OnError самой страницы.

Я думаю, что это работает только в .NET 4.0, поскольку свойство WebEventCode задокументировано как NEW в .NET 4.0.

protected override void OnError(EventArgs e)
{
    Exception err = Server.GetLastError();
    if (err is HttpException)
    {
        if ((err as HttpException).WebEventCode == 3004)
        {
            Context.Items["error"] = "File exceeded maximum allowed length.";
            Server.Transfer( Context.Request.Url.LocalPath );
            return;
        }
    }
    base.OnError(e);
}

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);
    if (!IsPostBack)
    {
        string error = Context.Items["error"] as string;
        if (!string.IsNullOrEmpty( error ))
            showErrorMessage( error );
    }
}

То, что я сделал, было:

  • получить последнюю ошибку с Server.GetLastError
  • проверьте, что это «Максимальная длина запроса превышена». ошибка (WebEventCode == 3004).
  • добавил значение в Context.Items коллекций, чтобы пометить запрос как ошибку
  • передать запрос обратно на саму страницу с помощью Server.Transfer (Context.Request.Url.LocalPath)
  • метод OnLoad страницы проверяет наличие флага ошибки и отображает сообщение, если оно присутствует

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

Также обратите внимание, что, хотя браузер в конечном итоге получит правильный ответ, браузер может потратить время на загрузку всего запроса, прежде чем он обработает ответ сервера и отобразит его. Такое поведение, вероятно, определяется как часть взаимодействия сервер / браузер в протоколе HTTP, поэтому, вероятно, с этим ничего не поделаешь.

...