Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 513|回复: 0

.NET MVC全局异常处理(一)

[复制链接]
  • TA的每日心情
    奋斗
    前天 08:53
  • 签到天数: 773 天

    [LV.10]以坛为家III

    2045

    主题

    2103

    帖子

    71万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    713646
    发表于 2021-6-1 13:32:07 | 显示全部楼层 |阅读模式

    .NET MVC全局异常处理

    一直知道有.NET有相关的配置,但没有实际做过,以为改下设定就可以,结果实际使用的时候还是遇到不少问题,所以要记录一下。

    IIS配置

    刚开始不想改程序代码,所以直接就想到了IIS里面的错误页配置配置,一开始反复测试,设置改了很多,但是没有效果,后来发现是静态页的配置,还没有进入MVC的程序部分,所以对于.NET MVC这种动态页是不生效的,应该使用.NET错误页选项

    静态错误页配置

    静态页配置流程如下:



    如上图所示,IIS中配置对错误的响应有三种方式,默认情况是第三个,本地访问显示详细错误信息,外部地址访问显示自定义页面,这样方便开发者调试,如果没有设置专门的错误页会使用IIS自带的样式,也就是第二张图中的配置,根据路径我们可以找到这样一个文件夹,里面都是错误提示的静态页,对应不同的状态代码

    我们可以把IIS设置为均使用自定义错误页看下效果,或者直接通过文件访问


    上面那张是详细的静态404错误,可以看到会暴露我们系统路径,下面则是默认的自定义错误页

    静态错误的默认页有相应的设置,看似可以修改,有“文件”、“执行URL”、“重定向”三种,但是实际设置一下就会发现报错:锁定错误

    通过这个错误我们去搜索解决方法可以看到一些人说将web.config中的httperror节下的defaultPath解锁即可,但似乎这是IIS7以前的设置,在IIS10中并没有相应的选项,看到一些说明提到可能是官方使用了更加安全的管理机制,因为发现这边的配置是静态页相关,不符合我的需要,没有深入研究,如果一定要使用这种可以看看这篇博客,试试能否通过系统命令解决锁定的问题

    win7 IIS Web.config节点锁定问题

    .NET错误页配置

    .NET错误页的设置与静态页差不多,除了入口不一样,配置的选项也不太相同,但是整体意思一样


    可以看到这里要求是绝对URL,所以实际使用起来应该是不太方便,所以没有找到太多相关资料。另外,需要web.conig中的customError设为On,部分异常如500会自动跳转到MVC的默认错误页Home/Error

    使用IIS的错误页处理虽然不用改代码,但是维护起来局限性很多,最终还是应该通过程序进行全局异常捕获

    程序设置

    通过程序控制的方法我想到两种,一个是使用全局配置文件Global.asax中的Application_Error方法,另一个是使用MVC的过滤器,默认的四种过滤器中就包含异常过滤

    全局异常配置

    这种方法对于WebForm和MVC都是通用的,在ASP.NET中,只要网站程序抛出未捕获的异常都会触发Application_Error事件。

    使用此方法一定要把GlobalFilter全局过滤器中的HandleErrorAttribute注册取消掉,也可以将配置文件中的customErrors节点关闭,否则HTTP 500的错误将不会被Application_Error事件捕获。


    捕获到异常之后我们可以很容易地跳转到静态页面

    protected void Application_Error(object sender, EventArgs e)
    {
        Exception exception = Server.GetLastError();
        var httpStatusCode = (exception as HttpException)?.GetHttpCode() ?? 700; //如果为空则走自定义
        var httpContext = ((MvcApplication)sender).Context;
        httpContext.ClearError();
    
        switch (httpStatusCode)
        {
            case 404:
                httpContext.Response.Redirect("~/Error/404.htm");
                break;
            default:
                httpContext.Response.Redirect("~/Error/500.htm");
                break;
        }
    }
    

    在一般情况下我们也可以指向一个控制器

    protected void Application_Error(object sender, EventArgs e)
    {
        Exception exception = Server.GetLastError();
        var httpStatusCode = (exception as HttpException)?.GetHttpCode() ?? 700; //如果为空则走自定义
        var httpContext = ((MvcApplication)sender).Context;
        httpContext.ClearError();
    
        var routeDic = new RouteValueDictionary
        {
            {"controller", "Home"},
            { "action","Error"}
        };
        httpContext.Response.RedirectToRoute("Default", routeDic);
    }
    

    但是在实际的业务中遇到了一些http请求的问题,在处理一部分代码抛出的异常时会出现“服务器无法在已发送HTTP标头之后······”这一系列异常,如“设置状态”、“追加标头”等,这个时候跳转要使用另一种写法

    protected void Application_Error(object sender, EventArgs e)
    {
        Server.ClearError();
        Response.TrySkipIisCustomErrors = true;
        var routeData = new RouteData();
        IController controller = new HomeController();
        routeData.Values.Add("controller", "Home");
        routeData.Values.Add("action", "Error");
        controller.Execute(new RequestContext(new HttpContextWrapper(Context), routeData));
        Response.End();
    }
    

    这里要注意的一点是如果要使用Area中的控制器不能写成routeData.Values.Add,而是使用DataTokens

    routeData.DataTokens.Add("area", "TestArea");
    
    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-8-11 03:26 , Processed in 0.063261 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表