14

我有一个 aspx 页面,允许用户上传文件,并且我想将最大文件上传大小限制为 10MB。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确实会提高。但是,当我玩 时maxAllowedContentLengthHttpApplication.Error不会引发事件,并且用户会被重定向到 404.13 页面。我已经附加了 Visual Studio,第一次机会异常打开,没有抛出任何异常。

我的第一个想法是在较早的事件中检查标题内容长度——是否有关于我在哪里执行此操作的建议/最佳实践?PostLogRequest?结束请求?

4

2 回答 2

15

在查看了 IIS 7.0 的 ASP.NET 应用程序生命周期概述并进行了我自己的实验之后,我假设请求验证是由 IIS 在引发任何事件之前在内部完成的。

看起来只有 LogRequest、PostLogRequest、EndRequest、PreSendRequestContent 和 PreSendRequestHeaders 在内部验证后引发此错误。

我决定HttpApplication.EndRequest在我的自定义错误处理程序中将事件处理程序附加到事件并检查 POST 上的 404.13 状态代码并在我需要处理时进行处理,在我的情况下是重定向到将检查的调用页面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);
    }
}

我欢迎对这种方法和替代方案提供反馈。

于 2009-02-20T21:31:54.880 回答
3

最简单的方法是在页面本身的 OnError 方法中处理。

我认为这仅适用于 .NET 4.0,因为 WebEventCode 属性在 .NET 4.0 中被记录为 NEW。

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 协议中服务器/浏览器交互的一部分,因此可能对此无能为力。

于 2011-04-15T05:48:28.220 回答