在實際的web開發中,經常會遇到以下情況,導致給用不好的體驗: a、程式未處理的異常,直接輸出顯示到用戶頁面 b、用戶訪問的資源不存在,直接顯示系統預設的404頁面 c、其它以下請求錯誤狀態的系統預設頁面(403等) 為了給用戶友好的體驗,在實際項目開發中, 需要對系統會... ...
問題描述:
在上一篇博文 “.net自定義錯誤頁面實現” 中已經介紹了在.net中如何實現自定義錯誤頁面實現(有需要者可以去上一篇博文瞭解),單純按照上一篇博文那樣設置,能夠實現所有請求的異常自定義跳轉,但是這樣又會產生一個問題:當通過ajax提交請求獲取介面提交請求,如果出現未處理的異常也會被重定向到自定義錯誤頁面。
針對ajax請求或者介面請求,這樣返回一個重定向頁面,用戶體驗顯然不是太友好,針對這個問題,下麵簡單總結一下我自己的想法和解決方案,當然不一定科學和合理,所以也希望有大牛多多指點。
解決思路,我想到的有二:
解決方案一:
從物理結構上分割,將web項目嚴格分割成兩個項目(當然可根據需要繼續細分):網站(只有網站頁面資源等內容)、介面(包括網站的所有數據邏輯處理,頁面的數據請求交互都是直接同介面交互(js技術)),
只是網站項目按照上一篇博文方式設置自定義錯誤頁面方式,這樣是能夠解決問題,項目也會更加的清晰,也有很多公司的項目就是按照這種方式(尤其是webApp),
但是在實際項目中,很多項目是沒有達到這種嚴格區分的,所以下麵的解決方案二,將介紹一個更通用的方式
解決方法二:
解決思路是:將上一篇博文 .net自定義錯誤頁面實現 與 上上一篇博文 .net捕捉全局未處理異常的3種方式 結合使用,併在實際開發中嚴格約定(出了url地址請求以外的其他請求都通過post請求實現交互),在撲捉到異常時,如果是post請求,處理異常,並清除異常。具體以步驟如下:
第一步:定義一個請求處理結果數據MODEL,代碼如下:
/// <summary> /// 請求結果MRequestResult /// </summary> public class MRequestResult { /// <summary> /// 請求結果編碼(是一個枚舉值) /// </summary> private RequestResultCodeEnum requestResultCode; /// <summary> /// 處理結果具體的返回值 /// </summary> private object resultValue; /// <summary> /// 請求結果編碼(是一個枚舉值) /// </summary> public RequestResultCodeEnum RequestResultCode { get { return this.requestResultCode; } set { this.requestResultCode = value; } } /// <summary> /// 處理結果具體的返回值 /// </summary> public object ResultValue { get { return this.resultValue; } set { this.resultValue = value; } } } /// <summary> /// 請求結果編碼枚舉值() /// </summary> public enum RequestResultCodeEnum { /// <summary> /// 請求成功 /// </summary> Success = 1, /// <summary> /// 請求失敗 /// </summary> Fail = -1, }
第二步:按照 上一篇博文: .net自定義錯誤頁面實現的步驟,配置好自定義錯誤頁面相關配置操作
第三步:按照 上上一篇博文:.net捕捉全局未處理異常的3種方式 的步驟實現全局異常為處理相關操作設置
第四步:在撲捉全局未處理的異常中,添加上針對post請求的異常處理過濾(直接輸入封裝後的),具體代碼如下:
/// <summary> /// 異常處理 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void context_Error(object sender, EventArgs e) { //此處處理異常 HttpContext ctx = HttpContext.Current; HttpResponse response = ctx.Response; HttpRequest request = ctx.Request; //獲取到HttpUnhandledException異常,這個異常包含一個實際出現的異常 Exception ex = ctx.Server.GetLastError(); //實際發生的異常 Exception iex = ex.InnerException; //// 異常日誌落地 //// 異常日誌落地包括:記錄異常文本文件日誌、或者記錄異常日誌資料庫等等(根據實際項目需要做記錄) //// 獲取請求方法 string httpMethod = request.HttpMethod; //// 如果是POST請求,那麼是以下請求之一 //// ajax介面請求 //// form表單提交 //// 這種情況的異常,不用跳轉至自已的異常錯誤頁面,直接返回對應系統異常 if (httpMethod.ToUpper() == "POST") { //// 構建返回對象值 MRequestResult requestResultM = new MRequestResult(); requestResultM.RequestResultCode = RequestResultCodeEnum.Fail; requestResultM.ResultValue = "系統異常,請聯繫管理員!"; response.Write(JsonConvert.SerializeObject(requestResultM, Formatting.Indented)); ctx.Server.ClearError();//處理完及時清理異常 } }
代碼實例:
ajax請求方法及其邏輯處理實例代碼:
$(function () { $.ajax({ async: true, type: "post", url: "../ActionTestResult/ContentResultTest", data: "name=xu", success: function (resultValue) { if (resultValue) { //// 解析處理結果 var resultObj = $.parseJSON(resultValue); //// 當RequestResultCode==1 說明該請求成功 ////(備註:並不代表處理成功,具體是否處理成功需要通過ResultValue的值根據介面約定解析做相應的邏輯處理) if (resultObj["RequestResultCode"] == 1) { //// 自定義請求成功邏輯處理 //// 通過解析具體的ResultValue的值做相應的邏輯處理..... if (resultObj["ResultValue"]) { var doResult = resultObj["ResultValue"].split('^'); if (doResult && doResult.length > 1) { if (doResult[0] == 1) { //// 說明處理成功,做相應的邏輯處理 alert("處理成功!"); } else { //// 處理失敗 alert(doResult[1]); } } else { alert("操作失敗!"); } } else { alert("未知結果"); } } else { //// 說明請求異常 //// 自定義邏輯處理 alert(resultObj["ResultValue"]); } } else { //// 自定義邏輯處理 alert("操作失敗!"); } console.log(resultValue); }, error: function (data) { //// 自定義邏輯處理 alert("系統異常,請聯繫管理員。電話:8888888"); console.log(data); } }); });
ajax對應的後臺請求接受實例代碼:
/// <summary> /// 測試 /// </summary> /// <returns></returns> public ContentResult ContentResultTest(string name) { //// 構建請求處理結果Model MRequestResult requestResultM = new MRequestResult() { RequestResultCode = RequestResultCodeEnum.Success }; //// 業務處理結果 string doResult = string.Empty; //// 本次自作簡單的參數非空判斷,只一個示例 //// 處理結果本例中也只是通過^鏈接表示,在實際處理過程中,可以將結果通過一個Json字元串 if (string.IsNullOrEmpty(name)) { doResult = "-1^操作失敗:名稱不能為空!"; } else { ///// 其他自定義業務邏輯處理,此處省略..... doResult = "1^操作成功"; } requestResultM.ResultValue = doResult; //// 返回結果 return Content(JsonConvert.SerializeObject(requestResultM, Formatting.Indented)); }
是不是覺得說的有點繞,本人表述能力有限,不懂的評論交流。
最後:個人能力有限也許該解決方式並不友好,有更好的解決方法,也歡迎留言交流,多多指點,多多指教