2009-04-23 16 views
64

Trong một trang web cũ, tôi đã thay đổi cách mà customErrors hoạt động bằng cách thêm redirectMode="ResponseRewrite" (mới trong 3.5 SP1):customErrors không hoạt động khi thiết redirectMode = "ResponseRewrite"

<customErrors mode="RemoteOnly" defaultRedirect="Error.aspx" redirectMode="ResponseRewrite"> 
    <error statusCode="404" redirect="404.aspx" /> 
</customErrors> 

Có điều là: nó cho thấy cho tôi trang lỗi chung (cái mà bạn nhận được khi bạn không đặt customErrors. Nếu tôi xóa phần redirectMode="ResponseRewrite", nó hoạt động tốt.

Tôi chắc chắn 3.5 SP1 được cài đặt trong máy chủ, vì tôi sử dụng cùng một cài đặt trên các trang web khác được lưu trữ trong cùng một máy chủ.

Bất kỳ ý tưởng nào?

Trả lời

1

Tôi thấy rằng sự cố xảy ra trong Error.aspx. Vẫn không thể tìm thấy lỗi thực tế trong error.aspx gây ra sự cố.

Thay đổi trang thành tệp html tĩnh đã giải quyết được sự cố.

9

Tôi biết câu hỏi này hơi cũ, nhưng tôi nghĩ tôi nên chỉ ra rằng nó không cần phải là một tệp tĩnh để làm việc này.

Tôi chạy vào một điều tương tự, và nó chỉ là vấn đề phát hiện lỗi trong Error.aspx của bạn, trong trường hợp của chúng tôi là vì trang chủ được sử dụng dựa trên một phần dữ liệu phiên và khi ResponseRewrite được đặt phiên không có sẵn cho trang Error.aspx của chúng tôi.

Tôi chưa tìm ra liệu tính không sẵn có của phiên này là do cấu hình ứng dụng cụ thể của chúng tôi hay phần "theo thiết kế" của ASP.net.

+0

Có, bạn đúng. Trong trường hợp của tôi, tôi không thể tìm thấy lỗi, vì vậy tôi đi an toàn với một HTML tĩnh. –

19

Điều đang xảy ra là IIS đang nắm bắt mã trạng thái lỗi và trình bày trang lỗi riêng của nó thay vì trang lỗi của bạn. Để giải quyết bạn cần phải thiết lập này trong mã đằng sau trang của trang lỗi của bạn để ngăn chặn IIS từ làm điều này:

Response.TrySkipIisCustomErrors = true; 

này sẽ chỉ làm việc trong IIS7 trở lên, đối với phiên bản trước của IIS bạn sẽ cần phải chơi với cài đặt trang lỗi.

+2

Cảm ơn - đây là giải pháp nếu bạn cần sử dụng trang .aspx làm defaultRedirect. – frankadelic

+1

Cảm ơn bạn đã nói với tôi về TrySkipIisCustomErrors. Tôi phải chuyển trở lại ResponseRedirect vì chúng ta phải gắn bó với IIS 6 mặc dù ... – Vinz

+0

Tôi đã thêm một chút thông tin về TrySkipIisCustomErrors trong câu trả lời http: // stackoverflow này.com/a/21271085/222748 – Michael

0

Trong trường hợp cụ thể của tôi, trang lỗi của tôi có trang chính có kiểm soát người dùng cố gắng sử dụng Phiên. Nếu Session không có sẵn, bạn nhận được một HttpException: "Session state chỉ có thể được sử dụng khi enableSessionState được đặt thành true, hoặc trong một tệp cấu hình hoặc trong chỉ thị trang." Sửa lỗi dễ nhất là chuyển sang html tĩnh, sửa lỗi dễ dàng nhất là sử dụng trang lỗi đơn giản hơn, khắc phục khó nhất là đảm bảo rằng trang lỗi của bạn không tạo bất kỳ giả định nào (ví dụ: Phiên đó sẽ không ném ngoại lệ) và không thể có lỗi.

91

Điều quan trọng cần lưu ý đối với bất kỳ ai cố gắng thực hiện việc này trong ứng dụng MVC là ResponseRewrite sử dụng Server.Transfer phía sau hậu trường. Do đó, defaultRedirect phải tương ứng với tệp hợp lệ trên hệ thống tệp. Rõ ràng, Server.Transfer không tương thích với các tuyến MVC, do đó, nếu trang lỗi của bạn được phục vụ bởi một hành động điều khiển, Server.Transfer sẽ tìm/Lỗi/Bất kỳ, không tìm thấy nó trên hệ thống tệp và trả lại trang lỗi 404 chung!

+0

Tôi cũng nhận thấy có sự cố với Biểu mẫu web và Định tuyến xem câu hỏi của tôi tại đây http://stackoverflow.com/questions/7269103/problem-with-defaultredirect-in-web-config-customerrors – GibboK

+0

Có một vấn đề CodePlex để cho phép ResponseRewrite hoạt động với các tuyến MVC, vui lòng bỏ phiếu: http://aspnet.codeplex.com/workitem/9034 – Dmitry

+1

@PussInBoots, đây là liên kết được lưu trữ https://web.archive.org/web/20131201222548/ http://aspnet.codeplex.com/workitem/9034 – KyleMit

0

Tôi đã phát hiện ra rằng nếu bạn sử dụng redirectMode = "ResponseRewrite" thì bạn cần phải thêm nội dung nào đó vào khu vực viết lại của tệp web.config. Vấn đề là khi trang web của bạn bị hỏng! Bạn không thể viết lại URL vì trang web của bạn không thể gọi "virtual.aspx" xử lý việc viết lại của bạn!

38

Cách duy nhất hoạt động hoàn hảo với tôi là tắt các lỗi tùy chỉnh và thay thế các trang lỗi của iis thông qua web.config. Nó gửi mã trạng thái chính xác với phản hồi và có lợi ích của việc không thông qua mvc.

đây là các mã

  1. Tắt lỗi tùy chỉnh

    <customErrors mode="Off" /> 
    
  2. Thay thế các trang lỗi

    <httpErrors errorMode="Custom" existingResponse="Replace"> 
        <remove statusCode="404" subStatusCode="-1" /> 
        <remove statusCode="500" subStatusCode="-1" /> 
        <error statusCode="404" path="Error404.html" responseMode="File" /> 
        <error statusCode="500" path="Error.html" responseMode="File" /> 
    </httpErrors> 
    

Note. Sử dụng responsemode="file" nếu url là một liên kết trực tiếp vào một tập tin

thông tin: http://tipila.com/tips/use-custom-error-pages-aspnet-mvc

+0

xem http://meta.stackexchange.com/a/22189/147333 để định dạng mã bên trong danh sách :) – CharlesB

+3

Tôi đã cố gắng hết sức để tìm ra "đúng "cách xử lý lỗi cho ứng dụng của tôi và đây là giải pháp. Tôi vẫn cần phải xử lý một số lỗi trong toàn cầu nhưng đó là OK vì tôi muốn những người đăng nhập. Khi điều đó xảy ra tôi đang làm một Server.Transfer đến một trang lỗi aspx. Phần lớn nhất của giải pháp này là người dùng không bao giờ biết những gì xử lý của tôi được đặt tên và không bao giờ được đưa đến một URL mà họ không yêu cầu. –

+1

Giải pháp này là hoàn hảo, nó sẽ thay thế các phản hồi lỗi AJAX và API http://stackoverflow.com/questions/24465261/customerrors-vs-httperrors-a-significant-design-flaw – Guillaume

1

tôi đã xây dựng một trang lỗi trong aspx mà chuyển các truy vấn đến một bộ điều khiển ASP.NET MVC. Bạn có thể viết lại truy vấn vào trang aspx này và nó sẽ chuyển truy vấn đến bộ điều khiển tùy chỉnh của bạn.

protected void Page_Load(object sender, EventArgs e) 
{ 
    //Get status code 
    var queryStatusCode = Request.QueryString.Get("code"); 
    int statusCode; 
    if (!int.TryParse(queryStatusCode, out statusCode)) 
    { 
    var lastError = Server.GetLastError(); 
    HttpException ex = lastError as HttpException; 
    statusCode = ex == null ? 500 : ex.GetHttpCode(); 
    } 
    Response.StatusCode = statusCode; 

    // Execute a route 
    RouteData routeData = new RouteData(); 
    string controllerName = Request.QueryString.Get("controller") ?? "Errors"; 
    routeData.Values.Add("controller", controllerName); 
    routeData.Values.Add("action", Request.QueryString.Get("action") ?? "Index"); 

    var requestContext = new RequestContext(new HttpContextWrapper(Context), routeData); 
    IController controller = ControllerBuilder.Current.GetControllerFactory().CreateController(requestContext, controllerName); 
    controller.Execute(requestContext); 
} 

Tìm thêm chi tiết ở đây: https://stackoverflow.com/a/27354140/143503

+0

Tôi kết hợp giải pháp được cung cấp ở đây với http : //stackoverflow.com/a/5536676/2310818 để xử lý tất cả các loại lỗi dù được gây ra do tuyến đường không xác định, bộ điều khiển không xác định, hành động không xác định, kết quả HttpNotFound() trả lại bởi hành động của bộ điều khiển và HttpException được điều khiển bởi một bộ điều khiển. Tôi đã đạt được tất cả điều này trong khi đạt được các mã trạng thái chính xác (404, 500) tùy thuộc vào loại mã lỗi. –

+1

@ ParthShah, nó đã làm việc với giải pháp này một mình nhưng có thể với một số hạn chế về cách bạn trả lại lỗi (ném một ngoại lệ thay vì trả về kết quả tôi đoán nhưng tôi không thực sự nhớ). Lỗi xử lý với ASP MVC/Web API và IIS là một nỗi đau, vui mừng khi bạn quản lý để làm cho nó hoạt động;) – Guillaume

9

Do sự phụ thuộc vào Server.Transfer có vẻ như việc thực hiện nội bộ của ResponseRewrite không tương thích với MVC.

Điều này có vẻ như một lỗ chức năng rõ ràng với tôi, vì vậy tôi quyết định triển khai lại tính năng này bằng mô-đun HTTP, để nó hoạt động. Giải pháp dưới đây cho phép bạn xử lý lỗi bằng cách chuyển hướng đến bất kỳ tuyến đường MVC hợp lệ nào (bao gồm cả tệp vật lý) giống như bạn thường làm.

<customErrors mode="RemoteOnly" redirectMode="ResponseRewrite"> 
    <error statusCode="404" redirect="404.aspx" /> 
    <error statusCode="500" redirect="~/MVCErrorPage" /> 
</customErrors> 

Điều này đã được thử nghiệm trên các nền tảng sau;

  • MVC4 tại Integrated Pipeline Mode (IIS nhanh 8)
  • MVC4 ở chế độ Cổ điển (VS Phát triển Server, Cassini)
  • MVC4 trong Classic Mode (IIS6)

namespace Foo.Bar.Modules { 

    /// <summary> 
    /// Enables support for CustomErrors ResponseRewrite mode in MVC. 
    /// </summary> 
    public class ErrorHandler : IHttpModule { 

     private HttpContext HttpContext { get { return HttpContext.Current; } } 
     private CustomErrorsSection CustomErrors { get; set; } 

     public void Init(HttpApplication application) { 
      System.Configuration.Configuration configuration = WebConfigurationManager.OpenWebConfiguration("~"); 
      CustomErrors = (CustomErrorsSection)configuration.GetSection("system.web/customErrors"); 

      application.EndRequest += Application_EndRequest; 
     } 

     protected void Application_EndRequest(object sender, EventArgs e) { 

      // only handle rewrite mode, ignore redirect configuration (if it ain't broke don't re-implement it) 
      if (CustomErrors.RedirectMode == CustomErrorsRedirectMode.ResponseRewrite && HttpContext.IsCustomErrorEnabled) { 

       int statusCode = HttpContext.Response.StatusCode; 

       // if this request has thrown an exception then find the real status code 
       Exception exception = HttpContext.Error; 
       if (exception != null) { 
        // set default error status code for application exceptions 
        statusCode = (int)HttpStatusCode.InternalServerError; 
       } 

       HttpException httpException = exception as HttpException; 
       if (httpException != null) { 
        statusCode = httpException.GetHttpCode(); 
       } 

       if ((HttpStatusCode)statusCode != HttpStatusCode.OK) { 

        Dictionary<int, string> errorPaths = new Dictionary<int, string>(); 

        foreach (CustomError error in CustomErrors.Errors) { 
         errorPaths.Add(error.StatusCode, error.Redirect); 
        } 

        // find a custom error path for this status code 
        if (errorPaths.Keys.Contains(statusCode)) { 
         string url = errorPaths[statusCode]; 

         // avoid circular redirects 
         if (!HttpContext.Request.Url.AbsolutePath.Equals(VirtualPathUtility.ToAbsolute(url))) { 

          HttpContext.Response.Clear(); 
          HttpContext.Response.TrySkipIisCustomErrors = true; 

          HttpContext.Server.ClearError(); 

          // do the redirect here 
          if (HttpRuntime.UsingIntegratedPipeline) { 
           HttpContext.Server.TransferRequest(url, true); 
          } 
          else { 
           HttpContext.RewritePath(url, false); 

           IHttpHandler httpHandler = new MvcHttpHandler(); 
           httpHandler.ProcessRequest(HttpContext); 
          } 

          // return the original status code to the client 
          // (this won't work in integrated pipleline mode) 
          HttpContext.Response.StatusCode = statusCode; 

         } 
        } 

       } 

      } 

     } 

     public void Dispose() { 

     } 


    } 

} 

Cách sử dụng

Bao gồm điều này làm mô-đun HTTP cuối cùng trong web.config

<system.web> 
    <httpModules> 
     <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" /> 
    </httpModules> 
    </system.web> 

    <!-- IIS7+ --> 
    <system.webServer> 
    <modules> 
     <add name="ErrorHandler" type="Foo.Bar.Modules.ErrorHandler" /> 
    </modules> 
    </system.webServer> 
+0

Cảm ơn bạn đã giải pháp. Tôi đã đặt mã vào global.asax nhưng trạng thái vẫn là 200. Để giải quyết vấn đề với pipleine tích hợp, chúng ta cần thiết lập trạng thái trước đó. Vì vậy, tôi đã có thể đặt nó trong hành động trang 404: [AllowAnonymous] hành động công cộngResult NotFound() { Response.StatusCode = 404; Chế độ xem trả lại ("NotFound"); } –

Các vấn đề liên quan