【问题标题】:Catch upload of to big files捕捉上传到大文件
【发布时间】:2026-02-03 12:35:01
【问题描述】:

Asp.Net 对文件上传有上限。我试图在服务器端捕捉这种情况。根据我找到的文档,应该可以覆盖 Global.asax 中的 Application_Error,但它对我不起作用。第二个选项是覆盖接收页面的 OnError,但这也不起作用。

谁能展示一些关于如何在服务器端捕获此错误的工作代码?

【问题讨论】:

    标签: asp.net error-handling file-upload


    【解决方案1】:

    首先你应该了解一些关于 maxRequestLength 的事情。使用服务器端方法验证,您无法预测文件大小。将值设置为高会增加 DoS 攻击的风险。 我在 web.config 中将 maxRequestLength 设置为 8MB:

     <httpRuntime maxRequestLength="8192" executionTimeout="3600" />
    

    如果用户上传的文件不大于 maxRequestLength 中给定的一半,我会检查表单的代码隐藏,但如果上传文件的大小大于 web 中指定的最大 RequestLength,则可能永远不会发生这种检查.config,因为会抛出异常。此类异常应在 Global.asax 级别上捕获。在那里我检查异常是否包含识别我们问题的单词,因为 System.Web.HttpUnhandledException 可以在许多其他情况下抛出!好的提示可能是检查异常来自哪个页面,以确保我们处理某些表单,将用户重定向回表单很重要。

    void Application_Error(object sender, EventArgs e){  
    Exception wyjatek = Server.GetLastError();
            if (wyjatek.InnerException != null && wyjatek.InnerException.Message.Contains("Maximum request length exceeded"))
            {
                Server.ClearError();
                Response.Redirect("FormWithFile.aspx?alert=Za-duzy-plik");
            }  
        }
    

    如果我在 Global.asax 中识别到此异常,我会将用户重定向到带有警报的页面(在 GET 中给出)。

    在我的 ASPX 页面代码隐藏中:

    首先我通过这棵树线从 web.config 中检索 MaxRequestLength 的值,并将其减半:

    static System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
    static HttpRuntimeSection section = config.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
    int maxFileSize = (section.MaxRequestLength/2)*1024; 
    

    然后在与插入按钮连接的操作中,我进行如下操作:

      protected void InsertButton_Click(object sender, EventArgs e)
            {
                if (((FileUpload)FormView1.FindControl("FileUpload1")).HasFile) // WHEN USER WANT TO UPLOAD FORM WITH FILE (its, optional)
                {
                    HttpPostedFile file = (HttpPostedFile)(((FileUpload)FormView1.FindControl("FileUpload1")).PostedFile);
                    int iFileSize = file.ContentLength;
                    if ((file != null) && (file.ContentLength > 0))
                    {
                       if (iFileSize > maxFileSize) // checking image SIZE!
                        { 
                            MessageForUser.Text = "<h1 class=error>Bad File! File is to big!</h1>";
                        }
                        else
                        {
                            byte[] plik = ((FileUpload)FormView1.FindControl("FileUpload1")).FileBytes;
                  // HERE COMES CODE FOR INSERT OF FORM WITH FILE
                            MessageForUser.Text = "<h1>Insert was sucessfull</h2>";
                        }
                    }
                }
                else
                {
                  // HERE COMES CODE FOR INSERT OF FORM WITHOUT FILE
                    MessageForUser.Text = "<h1>Insert was sucessfull</h2>";
            }
        }
    

    在 Page_Load 中,我还定义了如何从 Global.asax 检索 GET 给出的通信,以告知用户发生了什么。

     if (Request.QueryString["alert"]!=null)
                {
                    string temp =  Request.QueryString["alert"].Replace('-',' ');
                    MessageForUser.Visible = true;
                    MessageForUser.Text = "<h1 class=error>ERROR: " + temp + "</h1>";
                }   
    

    这个解决方案当然有它的缺点:

    1. 不过,我们可能会受到 8MB 文件的 DoS 攻击,我们首先在服务器级别识别,已经很晚了。
    2. 在从 Global.asax 重定向的情况下,用户表单的状态会丢失,但可以通过一些代码来克服。
    3. 用户体验相当差,因为服务器端的检查,以及许多用户的负载,应用程序可能会变慢。
    4. 临时到服务器来的文件甚至大于 8MB,但在 executionTimeout 中管理的文件

    可能的替代方案:

    1. 使用一些闪存技术在客户端检查文件大小
    2. 使用一些流技术,以小数据包的形式传输比特,当达到给定阈值时,抛出自己的异常并处理它。 适当阅读:Sending File in Chunks to HttpHandler

    【讨论】:

      【解决方案2】:

      在 Golobal.asax.cs 中添加以下内容:

      void Application_Error(Object sender, EventArgs e)
              {
                  HttpException ex = Server.GetLastError() as HttpException;
                  if (ex != null)
                  {
                      if ((ex.GetHttpCode() == 500 || ex.GetHttpCode() == 400) && ex.ErrorCode == -2147467259)
                      {
                          Server.ClearError();
                          Response.Redirect("~/MaximumFileError.aspx", false);
                      }
                  }
              }
      

      这对我有用,但我不确定它是否适用于所有情况。

      【讨论】:

        【解决方案3】:

        Uploadify 是一个 jquery 和 flash 上传器,允许您指定要下载的文件的最大大小。这样一来,您就可以防止用户首先下载文件,而不必担心之后会被捕获。

        【讨论】:

          【解决方案4】:

          “任何人都可以显示一些工作代码 如何在服务器上捕获此错误 一边?”

          不。无法使用代码来捕获此错误,因为它发生在任何代码启动之前。

          据我发现,您甚至无法为此错误指定替代错误页面,Web服务器只是在请求太大时拒绝接受。

          【讨论】:

          • 如果我在 web.config 中增加最大上传大小,它可以正常工作。所以上传必须被asp.net运行时的某些部分拦截。然后应该有可能以某种方式抓住这一点。你同意吗?
          • @Achim:如果您将限制设置得如此之高以至于实际上取消了限制,您可以在代码中进行检查,但是您的服务器很容易受到 DoS 攻击。有人可以开始一些大型上传,这会耗尽服务器中的所有 RAM。
          • 不,这取决于代码的执行位置和时间。我说的是:如果限制是在asp.ne运行时配置的,那么它也在asp.net运行时处理。所以请求至少到达 asp.net 并且在此之前没有被 IIS 阻止。然后应该有可能以某种方式在 asp.net 中捕获它。根据我提到的地方应该可能的文件 - 但它没有!?
          • @Achim:读了一点我发现你实际上可以在服务器端捕捉到错误,但这没什么用,因为服务器已经切断了连接以停止上传。您唯一能做的就是在服务器上记录错误,请求已经中止,因此您根本无法将任何内容发送回浏览器。
          【解决方案5】:

          您不能根据 web.config 文件中指定的最大大小检查文件大小,而不是捕获错误?您可以使用以下方法获取最大尺寸:

          System.Configuration.Configuration config = WebConfigurationManager.OpenWebConfiguration("~");
          HttpRuntimeSection section = config.GetSection("system.web/httpRuntime") as HttpRuntimeSection;
          double maxFileSize = section.MaxRequestLength;
          

          【讨论】:

          • 该代码将永远无法到达,因为 IIS 更早地拦截了上传。