抛出 HttpException 总是会发回 HTTP 500 错误?

问题描述 投票:0回答:4

我试图向客户端返回 HTTP 403 错误代码。我读过 HttpException 是完成此任务的最干净的方法,但它对我不起作用。我从这样的页面中抛出异常:

throw new HttpException(403,"You must be logged in to access this resource.");

但是,当 CustomErrors 关闭时,这只会提供标准的 ASP.Net 堆栈跟踪(带有 500 错误)。如果 CustomErrors 已打开,则不会重定向到我设置的在发生 403 错误时显示的页面。我应该忘记 HttpException 而自己设置所有 HTTP 代码吗?我该如何解决这个问题?

我的 Web.Config 的自定义错误部分是这样的:

<customErrors mode="On" defaultRedirect="GenericErrorPage.html">
      <error statusCode="403" redirect="Forbidden.html" />
</customErrors>

我将得到 GenericErrorPage.html,而不是 Forbidden.html

c# asp.net http httpexception
4个回答
8
投票

您需要像这样覆盖应用程序错误:

    protected void Application_Error()
    {
        var exception = Server.GetLastError();
        var httpException = exception as HttpException;
        Response.Clear();
        Server.ClearError();
        
        var routeData = new RouteData();
        routeData.Values["controller"] = "Errors";
        routeData.Values["action"] = "General";
        routeData.Values["exception"] = exception;
        Response.StatusCode = 500;

        if (httpException != null)
        {
            Response.StatusCode = httpException.GetHttpCode();
            switch (Response.StatusCode)
            {
                case 403:
                    routeData.Values["action"] = "Http403";
                    break;
                case 404:
                    routeData.Values["action"] = "Http404";
                    break;
            }
        }

        IController errorsController = new ErrorsController();
        var rc = new RequestContext(new HttpContextWrapper(Context), routeData);
        errorsController.Execute(rc);
    }

然后你必须添加错误控制器:

public class ErrorsController : Controller
{
    public ActionResult General(Exception exception)
    {
        ViewBag.ErrorCode = Response.StatusCode;
        ViewBag.Message = "Error Happened";

        //you should log your exception here

        return View("Index");
    }

    public ActionResult Http404()
    {
        ViewBag.ErrorCode = Response.StatusCode;
        ViewBag.Message = "Not Found";
        return View("Index");
    }

    public ActionResult Http403()
    {
        ViewBag.Message = Response.StatusCode;
        ViewBag.Message = "Forbidden";
        return View("Index");
    }

}

最后在错误控制器中创建一个视图。我只在 Views/Errors/ 中创建了一个名为 index 的视图。


3
投票

将此代码包含在 Web.config 文件的 configuration/system.web 元素中:

  <customErrors mode="On">
    <error statusCode="403" redirect="~/errors/Forbidden.aspx"/>
  </customErrors>

我设法让它按预期工作。

您可以在这里找到一个很好的教程和示例(示例 3 是正确的): http://aspnetresources.com/articles/CustomErrorPages

或者您可以使用 Response.Status 来执行此操作: Asp Classic 返回特定的http状态代码


1
投票

我实际上已经创建了自己的漂亮的小类来解决这个问题。它不能处理所有事情,我不确定它是否能与 MVC 配合良好,但它适合我的使用。基本上,它不会依赖 ASP.Net 输出正确的错误页面和错误代码,而是会清除错误,然后进行服务器端传输并显示相应的 Web.Config 错误页面。它还可以识别 customErrors 模式并做出相应的反应。

public static class CustomErrorsFixer
{
    static public void HandleErrors(HttpContext Context)
    {
        if(RunIt(Context)==false){
            return;
        }
        HttpException ex = Context.Error as HttpException;
        if(ex==null){
            try{
                ex=Context.Error.InnerException as HttpException;
            }catch{
                ex=null;
            }
        }

        if (ex != null){
            Context.Response.StatusCode = ex.GetHttpCode();
        }else{
            Context.Response.StatusCode = 500;
        }
        Context.ClearError();

        Context.Server.Transfer(GetCustomError(Context.Response.StatusCode.ToString()));
        HttpContext.Current.Response.End();
    }
    static protected string GetCustomError(string code)
    {
        CustomErrorsSection section = ConfigurationManager.GetSection("system.web/customErrors") as CustomErrorsSection;

        if (section != null)
        {
            CustomError page = section.Errors[code];

            if (page != null)
            {
                return page.Redirect;
            }
        }
        return section.DefaultRedirect;
    }
    static protected bool RunIt(HttpContext context){
        CustomErrorsSection section = ConfigurationManager.GetSection("system.web/customErrors") as CustomErrorsSection;
        switch(section.Mode){
            case CustomErrorsMode.Off:
                return false;
            case CustomErrorsMode.On:
                return true;
            case CustomErrorsMode.RemoteOnly:
                return !(context.Request.UserHostAddress=="127.0.0.1");
            default:
                return true;
        }
    }

}

然后要激活它,只需在 Global.asax 中添加一个小东西即可

    protected virtual void Application_Error (Object sender, EventArgs e)
    {
        CustomErrorsFixer.HandleErrors(Context);
    }

0
投票

我们正在将 System.Web.HttpApplication 用于应用程序,我发现的最简单的方法是创建一个 System.Net.Http.HttpResponseMessage (指定 System.Net.HttpStatusCode 以及可选的内容,例如System.Net.Http.StringContent)并将其扔进 System.Web.Http.HttpResponseException.

例如

using System.Net;
using System.Net.Http;
using System.Web.Http;
...

public class AController : ApiController
{
  ...
  public MyObject GetObject(int Id)
  {
    HttpResponseMessage resp;

    if (Id == null)
    {
      resp = new HttpResponseMessage(HttpStatusCode.BadRequest)
      {
        Content = new StringContent("An ID is required")
      };
      throw new HttpResponseException(resp);
    }

    var result = GetObject(Id);

    if (result == null)
    {
      resp = new HttpResponseMessage(HttpStatusCode.NotFound);
      throw new HttpResponseException(resp);
    }

    return result;
  }
  ...
}
© www.soinside.com 2019 - 2024. All rights reserved.