捕捉“超出最大请求长度”
我正在编写一个上传函数,并且在web.config(最大大小设置为5120)中的httpRuntime
中具有大于指定最大大小的文件时,遇到捕获“System.Web.HttpException:超出最大请求长度”的问题。 我正在使用一个简单的<input>
的文件。
问题是在上传button的点击事件之前抛出exception,并且在我的代码运行之前发生exception。 那么如何捕捉和处理exception呢?
编辑:exception即时抛出,所以我很确定这不是一个超时问题,由于连接速度慢。
不幸的是,没有简单的方法来捕捉这种exception。 我所做的是覆盖页面级别的OnError方法或global.asax中的Application_Error,然后检查它是否为最大请求失败,如果是,则转移到错误页面。
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。 如果上传速度太慢,您可能还需要更改executionTimeout。 请注意,您不希望这些设置中的任何一个太大,否则您将面临DOS攻击。
executionTimeout的默认值是360秒或6分钟。
您可以使用httpRuntime元素更改maxRequestLength和executionTimeout。
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>
编辑:
如果你想处理这个exception,就像已经说过的那样,你需要在Global.asax中处理它。 这是一个代码示例的链接。
您可以通过增加web.config中的最大请求长度来解决此问题:
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" /> </system.web> </configuration>
上面的例子是100Mb的限制。
嗨Damien McGivern提到的解决scheme,仅适用于IIS6,
它不适用于IIS7和ASP.NET开发服务器。 我得到页面显示“404 – 找不到文件或目录”。
有任何想法吗?
编辑:
知道了…这个解决scheme仍然不能在ASP.NET开发服务器上工作,但我得到了它在我的情况下不能在IIS7上工作的原因。
原因是IIS7有一个内置的请求扫描,强制上传文件上限默认为30000000字节(略低于30MB)。
我试图上传大小为100 MB的文件,以testingDamien McGivern提到的解决scheme(maxRequestLength =“10240”,即web.config中的10MB)。 现在,如果我上传大于10MB和小于30 MB的文件,那么页面将被redirect到指定的错误页面。 但是,如果文件大小> 30MB,那么它显示丑陋的内置错误页面显示“404 – 文件或目录未find。
所以,为了避免这种情况,你必须增加最大值。 允许在IIS7中为您的网站请求内容的长度。 这可以使用以下命令完成,
appcmd set config "SiteName" -section:requestFiltering -requestLimits.maxAllowedContentLength:209715200 -commitpath:apphost
我已经设置了最大值。 内容长度为200MB。
完成这个设置后,当我尝试上传100MB的文件时,页面成功地redirect到了我的错误页面
有关更多详细信息,请参阅http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx 。
如果你还想要一个客户端validation,所以你不需要抛出exception,你可以尝试实现客户端文件大小validation。
注意:这只适用于支持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>
一种方法是在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"; } }
这是另一种方式,不涉及任何“黑客”,但需要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 } }
与IIS7和更高版本一起使用的解决scheme: 当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在代码后面检查文件的大小,这会更好
你可能知道,最大的请求长度是在两个地方configuration的。
-
maxRequestLength
– 在ASP.NET应用程序级别控制 -
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(); } }
你可以通过在web.config中增加最大请求长度和执行时间来解决这个问题:
– 请澄清最大执行时间超过1200
<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>
标签后
<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添加到错误页面…
如何在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); } }