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

发布于 2024-10-31 13:55:22 字数 624 浏览 0 评论 0原文

我试图向客户端返回 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

I'm trying to throw an HTTP 403 error code back at the client. I've read that HttpException is the cleanest way to accomplish this, but it's not working for me. I throw the exception from within a page like this:

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

However, this will only give a standard ASP.Net stack trace(with 500 error) when CustomErrors is off. If CustomErrors is on, then this will not redirect to the page I have setup to be displayed when a 403 error occurs. Should I forget about HttpException and instead set all the HTTP codes myself? How do I fix this?

The custom errors part of my Web.Config is this:

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

Instead of getting Forbidden.html, I'll get GenericErrorPage.html

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

少跟Wǒ拽 2024-11-07 13:55:22

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

    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 的视图。

You need to override Application error like this:

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

Then you've got to add the errorsController:

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

}

And last create a view in for errorsController. I created just one view called index in Views/Errors/.

丿*梦醉红颜 2024-11-07 13:55:22

将此代码包含在 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 状态代码

With this code included in the element configuration/system.web of Web.config file:

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

I managed it to work as expected.

You can find a good tutorial with examples (example 3 is the right one) here:
http://aspnetresources.com/articles/CustomErrorPages

Or you may use Response.Status to do so:
Asp Classic return specific http status code

七禾 2024-11-07 13:55:22

实际上,我最终创建了自己的漂亮小课程来解决这个问题。它不能处理所有事情,我不确定它是否能与 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);
    }

I've actually ended up making my own nifty little class to fix this problem. It doesn't handle everything and I'm not sure it plays nice with MVC, but it works for my use. Basically, instead of relying on ASP.Net to output the correct error page and error code, it will clear the error and then do a server-side transfer and display the appropriate Web.Config error page. It also recognizes the customErrors mode and reacts accordingly.

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

}

And then to activate it, just add a small thing to Global.asax

    protected virtual void Application_Error (Object sender, EventArgs e)
    {
        CustomErrorsFixer.HandleErrors(Context);
    }
书间行客 2024-11-07 13:55:22

我们使用 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;
  }
  ...
}

We're using System.Web.HttpApplication for an app and this simplest way I've found is to create a System.Net.Http.HttpResponseMessage (specifying the System.Net.HttpStatusCode and optionally content like System.Net.Http.StringContent) and throw it in a System.Web.Http.HttpResponseException.

For example

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;
  }
  ...
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文