BeforeUnload事件下Asp.Net服务方法无法执行内部逻辑问题
问题:beforeunload事件关闭标签页时无法完整执行ASMX服务方法
实现代码
JavaScript 事件代码
$(window).on("beforeunload", function () { var d, str; str = '{Id:"' + $('#hdnId').val() + '"}'; d = str; $.ajax({ type: "POST", url: "../POC.asmx/fUpdateTimeInterval", data: d, contentType: "application/json; charset=utf-8", dataType: "json", async: true, beforeSend: function () { // BlockUI(); }, success: function (data, Type, xhr) { }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); }, complete: function () { }, failure: function () { } }); });
ASMX Web服务代码
[WebMethod(true)] public int fUpdateTimeInterval(String Id) { return new MY_POC.DLL.Survey().fUpdateTimeInterval(Id); }
DLL中的方法实现
public int fUpdateTimeInterval(Int32 Id) { List<SqlParameter> objParam = new List<SqlParameter>() { new SqlParameter{ParameterName ="@Id",Direction=ParameterDirection.Input,DbType=DbType.Int32,Value= Id}, }; MY_POC.DLL.SqlHelper.ExecuteNonQuery("MY_UpdateTimeInterval", System.Data.CommandType.StoredProcedure, objParam.ToArray()); return 0; }
问题现象
- 页面首次加载时可正常获取插入行的自动ID
- 刷新浏览器时,beforeunload事件触发后能正常更新对应ID的行
- 关闭标签页或浏览器时,服务方法仅进入方法开头,后续逻辑不执行且无报错,VS输出窗口仅显示相关提示
原因分析
关闭标签页/浏览器时,浏览器正执行页面卸载流程,此时异步AJAX请求(async: true)会被浏览器中断,无法完成后续数据库操作;而刷新页面时,浏览器卸载流程相对宽松,异步请求有足够时间完成。
解决方案
方案1:改为同步AJAX请求
将AJAX的async属性设为false,强制浏览器等待请求完成后再执行页面卸载:
$(window).on("beforeunload", function () { var d, str; str = '{Id:"' + $('#hdnId').val() + '"}'; d = str; $.ajax({ type: "POST", url: "../POC.asmx/fUpdateTimeInterval", data: d, contentType: "application/json; charset=utf-8", dataType: "json", async: false, // 修改为同步请求 beforeSend: function () { // BlockUI(); }, success: function (data, Type, xhr) { }, error: function (XMLHttpRequest, textStatus, errorThrown) { alert(errorThrown); } }); });
注意:同步请求可能导致页面卸载出现短暂延迟,部分现代浏览器可能对该操作有限制。
方案2:使用navigator.sendBeacon(推荐)
navigator.sendBeacon是浏览器专为页面卸载时发送数据设计的API,异步执行且浏览器会保证请求完成,不会阻塞页面卸载:
$(window).on("beforeunload", function () { var id = $('#hdnId').val(); var formData = new FormData(); formData.append("Id", id); navigator.sendBeacon("../POC.asmx/fUpdateTimeInterval", formData); });
同时修改ASMX方法适配FormData接收:
[WebMethod(true)] public int fUpdateTimeInterval() { string id = HttpContext.Current.Request.Form["Id"]; return new MY_POC.DLL.Survey().fUpdateTimeInterval(int.Parse(id)); }
内容的提问来源于stack exchange,提问作者Sumeet Kumar
相关产品推荐
相关产品推荐

