Nắm bắt được "Đã vượt quá độ dài yêu cầu tối đa"


112

Tôi đang viết hàm tải lên và gặp sự cố khi bắt "System.Web.HttpException: Đã vượt quá độ dài yêu cầu tối đa" với các tệp lớn hơn kích thước tối đa được chỉ định httpRuntimetrong web.config (kích thước tối đa được đặt thành 5120). Tôi đang sử dụng một đơn giản <input>cho tệp.

Vấn đề là ngoại lệ được đưa ra trước sự kiện nhấp chuột của nút tải lên và ngoại lệ xảy ra trước khi mã của tôi được chạy. Vậy làm cách nào để bắt và xử lý ngoại lệ?

CHỈNH SỬA: Ngoại lệ được đưa ra ngay lập tức, vì vậy tôi khá chắc chắn rằng đó không phải là vấn đề hết thời gian do kết nối chậm.


5
Có ai đã thử điều này với MVC? Tôi dường như có thể bắt được ngoại lệ theo đúng cách, nhưng tôi không thể ngăn nó lại: mỗi khi tôi cố gắng hiển thị một trang lỗi, một ngoại lệ giống nhau xảy ra.
Andy

Thông báo lỗi này được đưa ra bởi IIS trước khi đến bộ điều khiển. Để thông báo cho người dùng rằng tệp vượt quá giới hạn tải lên tối đa (được đặt trong cấu hình web của bạn), bạn có thể xác thực trực tiếp kích thước tệp qua JS với sự kiện onchange. Ví dụ: <input type="file" id="upload" name="upload" onchange="showFileSize();" />Inside showFileSize(), bạn có thể hiển thị thông báo lỗi dựa trên kích thước tệp của mình thông qua var input = document.getElementById("upload"); var file = input.files[0];và thêm thẻ html.
Alfred Wallace

Câu trả lời:


97

Không có cách nào dễ dàng để bắt một trường hợp ngoại lệ không may như vậy. Những gì tôi làm là ghi đè phương thức OnError ở cấp độ trang hoặc Application_Error trong global.asax, sau đó kiểm tra xem đó có phải là lỗi Yêu cầu tối đa không và nếu có, hãy chuyển sang trang lỗi.

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

Đó là một cuộc tấn công nhưng đoạn mã dưới đây phù hợp với tôi

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

2
Cảm ơn. OnError không hoạt động, nhưng Application_Error thì có. Chúng tôi thực sự có một trình xử lý cho việc này, nhưng ai đó đã tắt nó trong mã.
Marcus L

thậm chí hai năm trước, nhưng tôi vẫn muốn hỏi liệu điều này có hoạt động tốt cho đến bây giờ không? so sánh chuỗi của 'GetEntireRawContent' có hoạt động tốt không? Tôi không nghĩ rằng đây là một vấn đề thời gian chờ. có ai đứng ra chỉ cho tôi nói xấu ở đâu đó về việc này không?
Elaine

@Elaine vâng, kỹ thuật này vẫn hoạt động với ASP.Net 4.0. Nếu bạn cố gắng tải lên một yêu cầu lớn hơn độ dài yêu cầu tối đa, ASP.Net sẽ ném một HttpException với mã thời gian chờ. Hãy xem trong System.Web.HttpRequest.GetEntireRawContent () bằng cách sử dụng phản xạ.
Damien McGivern

12
@ sam-rueby Tôi không muốn trả lời thông báo lỗi chuỗi có thể thay đổi do bản địa hóa.
Damien McGivern

4
Đối với .NET 4.0 trở lên, có cách tốt hơn để xác định xem kích thước yêu cầu tối đa có bị vượt quá hay không. Bạn có thể kiểm tra điều kiện này cho HttpException: httpException.WebEventCode == WebEventCodes.RuntimeErrorPostTooLarge- sử dụng System.Web.Management.WebEventCodes
mco

58

Như GateKiller đã nói bạn cần thay đổi maxRequestLength. Bạn cũng có thể cần thay đổi thời gian thực thi trong trường hợp tốc độ tải lên quá chậm. Lưu ý rằng bạn không muốn một trong hai cài đặt này quá lớn nếu không bạn sẽ dễ bị tấn công DOS.

Thời gian chờ mặc định là 360 giây hoặc 6 phút.

Bạn có thể thay đổi maxRequestLength và executeTimeout bằng Phần tử httpRuntime .

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <httpRuntime maxRequestLength="102400" executionTimeout="1200" />
    </system.web>
</configuration>

BIÊN TẬP:

Nếu bạn muốn xử lý ngoại lệ bất kể thì như đã nêu, bạn sẽ cần xử lý nó trong Global.asax. Đây là một liên kết đến một ví dụ mã .


2
Cảm ơn câu trả lời của bạn, nhưng như tôi đã nói trong nhận xét của tôi cho câu trả lời của GK, điều này không thực sự giải quyết được vấn đề của tôi. Đó cũng không phải là vấn đề thời gian chờ, vì ngoại lệ được ném ra ngay lập tức. Tôi sẽ chỉnh sửa câu hỏi để làm rõ hơn.
Marcus L

4
Url ví dụ mã trỏ đến một trang không có sẵn ... có ai có thể sửa lỗi này không?
hủy đăng ký

20

Bạn có thể giải quyết vấn đề này bằng cách tăng độ dài yêu cầu tối đa trong web.config của mình:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
    <system.web>
        <httpRuntime maxRequestLength="102400" />
    </system.web>
</configuration>

Ví dụ trên dành cho giới hạn 100Mb.


18
Có và không. Bạn đẩy giới hạn xa hơn, nhưng nó không thực sự xử lý ngoại lệ. Bạn sẽ vẫn gặp sự cố tương tự nếu ai đó cố tải lên 101 Mb trở lên. Giới hạn thực sự cần phải là 5 Mb.
Marcus L

10

Nếu bạn cũng muốn xác thực phía máy khách để bạn bớt phải ném các ngoại lệ, bạn có thể thử triển khai xác thực kích thước tệp phía máy khách.

Lưu ý: Điều này chỉ hoạt động trong các trình duyệt hỗ trợ 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>


9

Hi giải pháp được đề cập bởi Damien McGivern, Chỉ hoạt động trên IIS6,

Nó không hoạt động trên IIS7 và ASP.NET Development Server. Tôi nhận được trang hiển thị "404 - Không tìm thấy tệp hoặc thư mục."

Có ý kiến ​​gì không?

BIÊN TẬP:

OK ... Giải pháp này vẫn không hoạt động trên Máy chủ phát triển ASP.NET, nhưng tôi đã hiểu lý do tại sao nó không hoạt động trên IIS7 trong trường hợp của tôi.

Lý do là IIS7 có tính năng quét yêu cầu tích hợp áp đặt giới hạn tệp tải lên được mặc định là 30000000 byte (nhỏ hơn một chút là 30MB).

Và tôi đang cố gắng tải lên tệp có kích thước 100 MB để kiểm tra giải pháp được đề cập bởi Damien McGivern (với maxRequestLength = "10240" tức là 10MB trong web.config). Bây giờ, Nếu tôi tải lên tệp có kích thước> 10MB và <30 MB thì trang được chuyển hướng đến trang lỗi đã chỉ định. Nhưng nếu kích thước tệp> 30MB thì nó sẽ hiển thị trang lỗi tích hợp xấu xí hiển thị "404 - Không tìm thấy tệp hoặc thư mục."

Vì vậy, để tránh điều này, bạn phải tăng tối đa. độ dài nội dung yêu cầu được phép cho trang web của bạn trong IIS7. Điều đó có thể được thực hiện bằng lệnh sau,

appcmd set config "SiteName" -section:requestFiltering -requestLimits.maxAllowedContentLength:209715200 -commitpath:apphost

Tôi đã đặt giá thầu tối đa. nội dung dài 200MB.

Sau khi thực hiện cài đặt này, trang được chuyển hướng thành công đến trang lỗi của tôi khi tôi cố gắng tải lên tệp 100MB

Tham khảo, http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx để biết thêm chi tiết.


Lấy làm tiếc! Tôi đã thêm truy vấn của mình dưới dạng Câu trả lời, tôi không biết làm cách nào để thêm nhận xét vào các bài đăng hiện có.
Vinod T. Patil

1
Bạn chỉ cần thêm đại diện. để bình luận bài viết. Xem câu hỏi thường gặp để biết thêm chi tiết về những gì bạn có thể / không thể làm với đại diện hiện tại của mình.
vui vẻ

7

Đây là một cách thay thế, không liên quan đến bất kỳ "hack" nào, nhưng yêu cầu ASP.NET 4.0 trở lên:

//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
    }
}

4

Một cách để làm điều này là đặt kích thước tối đa trong web.config như đã được nêu ở trên, ví dụ:

<system.web>         
    <httpRuntime maxRequestLength="102400" />     
</system.web>

sau đó khi bạn xử lý sự kiện tải lên, hãy kiểm tra kích thước và nếu nó vượt quá một số lượng cụ thể, bạn có thể bẫy nó, ví dụ:

protected void btnUploadImage_OnClick(object sender, EventArgs e)
{
    if (fil.FileBytes.Length > 51200)
    {
         TextBoxMsg.Text = "file size must be less than 50KB";
    }
}

1
Điều này không hiệu quả. Sự kiện nhấp chuột không bao giờ được kích hoạt. Ngoại lệ xảy ra trước đây.
Lombas


3

Trong IIS 7 và hơn thế nữa:

tệp web.config:

<system.webServer>
  <security >
    <requestFiltering>
      <requestLimits maxAllowedContentLength="[Size In Bytes]" />
    </requestFiltering>
  </security>
</system.webServer>

Sau đó, bạn có thể kiểm tra mã phía sau, như sau:

If FileUpload1.PostedFile.ContentLength > 2097152 Then ' (2097152 = 2 Mb)
  ' Exceeded the 2 Mb limit
  ' Do something
End If

Chỉ cần đảm bảo [Kích thước tính bằng byte] trong web.config lớn hơn kích thước tệp bạn muốn tải lên thì bạn sẽ không gặp lỗi 404. Sau đó, bạn có thể kiểm tra kích thước tệp bằng mã đằng sau bằng cách sử dụng ContentLength, điều này sẽ tốt hơn nhiều


2

Như bạn có thể biết, độ dài yêu cầu tối đa được định cấu hình ở HAI vị trí.

  1. maxRequestLength - được kiểm soát ở cấp ứng dụng ASP.NET
  2. maxAllowedContentLength- dưới sự <system.webServer>kiểm soát ở cấp độ IIS

Trường hợp đầu tiên được bao gồm bởi các câu trả lời khác cho câu hỏi này.

Để bắt THE SECOND ONE, bạn cần thực hiện điều này trong 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();
    }
}

1

Sau thẻ

<security>
     <requestFiltering>
         <requestLimits maxAllowedContentLength="4500000" />
     </requestFiltering>
</security>

thêm thẻ sau

 <httpErrors errorMode="Custom" existingResponse="Replace">
  <remove statusCode="404" subStatusCode="13" />
  <error statusCode="404" subStatusCode="13" prefixLanguageFilePath="" path="http://localhost/ErrorPage.aspx" responseMode="Redirect" />
</httpErrors>

bạn có thể thêm Url vào trang lỗi ...


0

Bạn có thể giải quyết vấn đề này bằng cách tăng thời lượng yêu cầu tối đa và thời gian thực thi trong web.config của bạn:

-Xin vui lòng làm rõ thời gian thực hiện tối đa sau đó là 1200

<?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <httpRuntime maxRequestLength="102400" executionTimeout="1200" /> </system.web> </configuration>

0

Làm thế nào về việc bắt nó tại sự kiện 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);
        }
    }

0

Nó có thể được kiểm tra thông qua:

        var httpException = ex as HttpException;
        if (httpException != null)
        {
            if (httpException.WebEventCode == System.Web.Management.WebEventCodes.RuntimeErrorPostTooLarge)
            {
                // Request too large

                return;

            }
        }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.