当前位置: 首页 > news >正文

[ASP.NET MVC]Ajax与CustomErrors的尴尬

在ASP.NET程序中,为了给用户显示友好的错误信息,通常在web.config中进行如下的设置:

<customErrors mode="RemoteOnly" defaultRedirect="/error/error.htm">
</customErrors>

但如果是一个ajax请求在服务端发生了错误,将遭遇一个尴尬。我们就遭遇过这样的尴尬,见下图:

上图中显示“抱歉!系统发生了错误!”的地方是ajax加载的内容,ajax部分的js代码如下:

$.ajax({            
    success: function (data) {
        if (data) {
            resultElement.html(data);
        }
    }
});

从上面的代码可以知道,虽然ajax请求出错,但依然在success回调函数中处理了,导致将定制错误信息作为正常返回内容显示出来,从而造成前图中的尴尬。

刚面对这个问题时,我们想到的解决方法是根据statusCode进行判断,如果是500,就知道是发生了错误,然后进行特定的错误处理。我们写了这样的测试代码:

$.ajax({
    statusCode: {
        500: function () {
            console.log('error!');
        }
    },
    success: function (data) {
        if (data) {
            resultElement.html(' ' + data);
        }
    }
});

结果发现,并没有执行对应于500 statusCode的回调函数。

在浏览器中查看了一下,原来服务器端返回的是302状态码。也就是说,在默认情况下,ASP.NET用重定向的方式向浏览器返回定制错误信息。在web.config>CustomErrors中,有个专门的属性redirectMode,其默认值就是ResponseRedirect。redirectMode还有个值是ResponseRewrite,能不能解决我们的问题呢?我们改一下web.config试一试,修改如下:

<customErrors mode="RemoteOnly" defaultRedirect="/error/error.htm" redirectMode="ResponseRewrite">
</customErrors>

结果发现,的确是返回500状态码了,但定制错误错误没了,返回的是Runtime Error。

当设置redirectMode="ResponseRewrite",发生错误时,ASP.NET实际会执行Server.Transfer()返回定制错误信息页面,而Server.Transfer()与ASP.NET MVC路由存在兼容问题,详见CustomErrors does not work when setting redirectMode=“ResponseRewrite”。

服务端暂时找不到解决方法,从浏览器端下手试试。

我们想到一个解决思路,就是根据302 statusCode进行处理,根据我们的实际场景(redirectMode是默认值ResponseRedirect),如果服务端返回的是302,肯定是发生了错误。于是,我们改为如下的ajax代码:

$.ajax({
    statusCode: {
        302: function () {
            console.log('error!');
        }
    },
    success: function (data) {
        if (data) {
            resultElement.html(' ' + data);
        }
    }
});

结果发现,并没有执行302的回调函数,也就是说ajax请求根本拿不到302状态码(http status code),实际得到的还是200状态码。

既然浏览器端也找不到解决方法,只有“回头是岸”,回到服务器端。

既然CustomErrors解决不了问题,那我们就把它给废了:

<customErrors mode="Off">
</customErrors>

然后自己处理定制错误信息,在Global.asax.cs中添加如下的代码:

protected void Application_Error(Object sender, EventArgs e)
{
    Exception lastError = Server.GetLastError();
    if (lastError != null)
    {
        Response.StatusCode = 500;
        Response.WriteFile("~/error/error.htm");
        Server.ClearError();
    }                        
}

问题就这样解决了!

另外,不用默认的“重定向显示定制错误信息”方式还有一个很大的好处,在发生错误时,浏览器地址栏不会跳转,这样用户反馈错误时,可以直接反馈发生问题时实际访问的完整网址。截个图纪念一下CustomErrors曾经带来的烦恼。

相关文章:

  • 【我眼中的戴尔转型】(四)惠普之道,月亮的脸悄悄地在改变
  • 图书推荐:《iOS软件开发兵法:应用程序与游戏开发之道》
  • php的时间戳与日期
  • @拔赤:Web前端开发十日谈
  • ORACLE实例RENAME,DB_LINK同步(Materialized View,Snapshot)
  • windows之ping
  • [原][linux]踢出某正在访问的用户||永久禁止某IP访问
  • 水鱼五笔编码练习系统
  • Android工程 引用另外一个Android工程
  • spring @Autowired 与@Resource的区别
  • Server 2008R2创建RDP-TCP连接方式
  • 在无VS开发环境的情况下调用Asp.net网站配置工具{转}
  • WM_NOTIFY消息流程实例分析 .
  • 海洋MP3播放器
  • 层被Flash挡住
  • ----------
  • 「译」Node.js Streams 基础
  • avalon2.2的VM生成过程
  • CSS 提示工具(Tooltip)
  • C语言笔记(第一章:C语言编程)
  • ES6 ...操作符
  • java2019面试题北京
  • October CMS - 快速入门 9 Images And Galleries
  • PHP的类修饰符与访问修饰符
  • Quartz初级教程
  • Shell编程
  • Unix命令
  • webpack+react项目初体验——记录我的webpack环境配置
  • 创建一种深思熟虑的文化
  • 二维平面内的碰撞检测【一】
  • 高度不固定时垂直居中
  • 工作踩坑系列——https访问遇到“已阻止载入混合活动内容”
  • 关键词挖掘技术哪家强(一)基于node.js技术开发一个关键字查询工具
  • 浏览器缓存机制分析
  • 前端存储 - localStorage
  • 使用 Docker 部署 Spring Boot项目
  • 使用common-codec进行md5加密
  • 写代码的正确姿势
  • 自制字幕遮挡器
  • 《TCP IP 详解卷1:协议》阅读笔记 - 第六章
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • # C++之functional库用法整理
  • # 再次尝试 连接失败_无线WiFi无法连接到网络怎么办【解决方法】
  • #pragma multi_compile #pragma shader_feature
  • #宝哥教你#查看jquery绑定的事件函数
  • #周末课堂# 【Linux + JVM + Mysql高级性能优化班】(火热报名中~~~)
  • (2.2w字)前端单元测试之Jest详解篇
  • (js)循环条件满足时终止循环
  • (ZT)北大教授朱青生给学生的一封信:大学,更是一个科学的保证
  • (八)Flask之app.route装饰器函数的参数
  • (笔试题)分解质因式
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (转)Spring4.2.5+Hibernate4.3.11+Struts1.3.8集成方案一
  • (转)从零实现3D图像引擎:(8)参数化直线与3D平面函数库
  • * 论文笔记 【Wide Deep Learning for Recommender Systems】