我希望能够在以下情况下显示特定的自定义错误页面:
web.config中有两个区域可以控制自定义错误-system.web\customErrors和system.webServer\httpErrors。
我已经使用customErrors部分以及Global.asax.cs中的一些逻辑来使#1,#2工作,并且我已经使用了httpErrors部分来使#3和#4工作。
我的问题是,当我同时实现了customErrors和httpErrors部分时,#2(拒绝访问)不起作用如果我不使用httpErrors部分,则它可以工作,但是我无法处理请求大小超出或找不到页面(对于非asp.net资源)。我现在很难同时满足所有4个要求。
这是我的实现方式
System.web \ customErrors仅可以控制由ASP.NET处理资源导致的自定义错误处理,而system.webServer \ httpErrors控制由IIS应用于任何资源的自定义错误处理。
首先,我设置了httpErrors:
<httpErrors errorMode="Custom" existingResponse="Replace" defaultResponseMode="Redirect" >
<!--Server Error-->
<remove statusCode="500" subStatusCode="-1" />
<error statusCode="500" path="/ErrorPages/ApplicationError.aspx" responseMode="Redirect" />
<!--Request Size Exceeded (upload too big) -->
<!--This only works if the security\requestFiltering\requestLimits are defined. If it is not defined, the response status code is 500 (internal server error) -->
<remove statusCode="404" subStatusCode="13" />
<error statusCode="404" subStatusCode="13" path="/ErrorPages/RequestSizeExceeded.aspx" responseMode="Redirect" />
<!--Page Not Found-->
<remove statusCode="404" subStatusCode="-1" />
<error statusCode="404" subStatusCode="-1" path="/ErrorPages/NotFound.aspx" responseMode="Redirect" />
</httpErrors>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="4194304" ></requestLimits>
</requestFiltering>
</security>
上述设置为我提供了一个针对一般错误(500),请求大小太大(404.13)和找不到页面(404)的自定义错误页面(对于asp.net和非asp.net处理的资源)。
剩下的是访问被拒绝的自定义错误页面。为此,我将结合使用web.config中的customErrors部分和Global.asax文件中的逻辑:
<customErrors mode="On" defaultRedirect="~/ErrorPages/ApplicationError.aspx?customErrors">
<!--404 - Page Not Found-->
<error statusCode="404" redirect="~/ErrorPages/NotFound.aspx?customErrors" />
<!--401 - Access Denied-->
<error statusCode="401" redirect="~/ErrorPages/AccessDenied.aspx?customErrors" />
</customErrors>
Global.asax.cs:
/// <summary>
/// Check the response status. If it is an access denied, redirect to the access denied error page if configured in the web.config file.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Application_EndRequest(object sender, EventArgs e)
{
//Because it is not possible to redirect to a custom error page using the web.config customErrors element for an access denied (401) error, we need to handle that here.
/*
The way wininet authentication works is that if the resource you are requesting does not allow anonymous access, a 401 is sent back to the browser.
If the resource is using Windows Integrated authentication and the browser is configured to automatically send credentials,
the token is sent back and the user is authenticated. In the case of Basic authentication, a login prompt is displayed and the user must log in.
If you intercept the 401 and redirect somewhere, you hijack the browser's ability to challenge.
1. The browser sends request without credentials to the server.
2. Server rejects this request and answers with "401 Access Denied".
3. Browser recognizes 401 and if it has appropriate credentials does not show this message. The second request with credentials will be posted. The requested page will be sent to the browser.
4. If the browser has no credentials the second post will not take place. The received "401 Access Denied" will be shown.
The work around works as follows:
1. The browser sends request without credentials to the server.
2. Server rejects this request and answers with "401 Access Denied" Header + our JavaScript.
3. Browser recognizes 401 and if it has appropriate credentials does not show this message.
Our HTML will not be rendered and JavaScript will not be executed. The second request with credentials will be posted. The requested page will be sent to the browser.
4. If the browser has no credentials, the second post will not take place. The received "401 Access Denied" will be shown.
Our HTML will be rendered and JavaScript will be executed. The client side redirection will take place. The browser will show a custom 401 page.
*/
HttpContext context = HttpContext.Current;
if (context.Response != null &&
context.Response.StatusCode == 401)
{
string sPage = GetCustomErrorPage(context.Response.StatusCode.ToString());
if (!string.IsNullOrEmpty(sPage))
{
//Instruct the client to redirect to a custom error page
sPage = System.Web.VirtualPathUtility.ToAbsolute(sPage);
context.Response.ClearContent();
context.Response.Write("<script language=\"javascript\">self.location='" + sPage + "';</script>");
}
}
}
/// <summary>
/// Returns the url of a custom error page as defined in the web config.
/// </summary>
/// <param name="sErrorCode">Http error code</param>
/// <returns>Returns the url of a custom error page for a specific error code, as defined in the web.config file. Returns null if not defined.</returns>
private string GetCustomErrorPage(string sErrorCode)
{
System.Web.Configuration.CustomErrorsSection lstErrors = (System.Web.Configuration.CustomErrorsSection)System.Web.Configuration.WebConfigurationManager.GetWebApplicationSection("system.web/customErrors");
if (lstErrors != null)
{
System.Web.Configuration.CustomError error = lstErrors.Errors[sErrorCode];
if (error != null)
{
return error.Redirect;
}
}
return null;
}