ASP.NET文件下载完成后JavaScript加载器无法隐藏问题
问题原因
当触发文件下载时,后端执行Response.End()会立即终止HTTP响应,后续注册的HideLoader()脚本根本不会被发送到客户端;同时文件下载是独立的响应流,不会触发页面刷新,即使没有Response.End(),后端注册的脚本也无法在当前页面执行,导致加载器一直显示。
解决方案1:AJAX+Blob异步下载(推荐)
将同步提交改为AJAX请求,后端返回文件字节流,前端通过Blob创建下载链接,全程可控加载器显示隐藏。
前端代码修改
<div id="ContentPlaceHolder1_divShowLoadingGif" class="dvLoader" style="display: none;"> <img id="img2" alt="" src="images/1487.png" /> </div> <button id="ContentPlaceHolder1_btnDownloadInfo" class="btn btn-primary downnloadReport">Report Download</button> <script> function showloadingGif_UPLOAD() { document.getElementById('ContentPlaceHolder1_divShowLoadingGif').style.display = 'inline'; } function HideLoader() { document.getElementById('ContentPlaceHolder1_divShowLoadingGif').style.display = 'none'; } // 绑定按钮点击事件 document.getElementById('ContentPlaceHolder1_btnDownloadInfo').addEventListener('click', function() { showloadingGif_UPLOAD(); const dateFilter = document.getElementById('<%= txtDateSelection.ClientID %>').value; fetch('<%= ResolveUrl("~/YourPage.aspx/DownloadReportAsync") %>', { method: 'POST', headers: { 'Content-Type': 'application/json; charset=utf-8' }, body: JSON.stringify({ strDateFilter: dateFilter }) }) .then(response => { if (!response.ok) throw new Error('请求失败'); return response.blob(); }) .then(blob => { // 创建并触发下载链接 const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = `JIO_LOS_REPORT_${new Date().toString()}.xlsx`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); }) .catch(err => { alert('下载失败:' + err.message); }) .finally(() => { // 无论成功失败都隐藏加载器 HideLoader(); }); }); </script>
后端新增异步Web方法
[WebMethod] public static byte[] DownloadReportAsync(string strDateFilter) { DataTable dtExcelData = new DataTable(); try { CommonUser ObjUser = new CommonUser(); dtExcelData = ObjUser.GET_EXCEL_REPORT(strDateFilter); if (dtExcelData == null || dtExcelData.Rows.Count == 0) { throw new Exception("No record found"); } using (XLWorkbook wb = new XLWorkbook()) { wb.Worksheets.Add(dtExcelData, "SheetName"); using (MemoryStream ms = new MemoryStream()) { wb.SaveAs(ms); return ms.ToArray(); } } } catch (Exception ex) { string strErrorMsg = ex.Message.ToString() + " " + "StackTrace :" + ex.StackTrace.ToString(); CommonDB.WriteLog("ERROR:" + strErrorMsg, ConfigurationManager.AppSettings["AIRFIBER_LOG"].ToString()); throw ex; } }
解决方案2:Cookie检测加载器隐藏
如果不想修改为AJAX,可在后端下载完成后设置Cookie,前端定时检测Cookie状态来隐藏加载器。
后端DownloadReport方法修改
public static void DownloadReport(DataTable dtRecord) { try { string strFilename = string.Empty; using (XLWorkbook wb = new XLWorkbook()) { wb.Worksheets.Add(dtRecord, "SheetName"); strFilename = DateTime.Now.ToString(); HttpContext.Current.Response.Clear(); HttpContext.Current.Response.Buffer = true; HttpContext.Current.Response.Charset = ""; HttpContext.Current.Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"; HttpContext.Current.Response.AddHeader("content-disposition", "attachment;filename=JIO_LOS_REPORT_"+ strFilename +".xlsx"); // 设置下载完成标识Cookie HttpContext.Current.Response.Cookies.Add(new HttpCookie("DownloadComplete", "true") { Expires = DateTime.Now.AddMinutes(1) }); using (MemoryStream MyMemoryStream = new MemoryStream()) { wb.SaveAs(MyMemoryStream); MyMemoryStream.WriteTo(HttpContext.Current.Response.OutputStream); HttpContext.Current.Response.Flush(); // 用Close替代End,避免终止响应导致Cookie无法写入 HttpContext.Current.Response.Close(); } } } catch (Exception ex) { string strErrorMsg = ex.Message.ToString() + " " + "StackTrace :" + ex.StackTrace.ToString(); CommonDB.WriteLog("ERROR:" + strErrorMsg, ConfigurationManager.AppSettings["AIRFIBER_LOG"].ToString()); } }
前端新增检测脚本
<script> function showloadingGif_UPLOAD() { document.getElementById('ContentPlaceHolder1_divShowLoadingGif').style.display = 'inline'; // 启动定时检测 checkDownloadComplete(); } function HideLoader() { document.getElementById('ContentPlaceHolder1_divShowLoadingGif').style.display = 'none'; } function checkDownloadComplete() { const interval = setInterval(() => { const cookie = document.cookie.split('; ').find(row => row.startsWith('DownloadComplete=')); if (cookie) { HideLoader(); // 清除Cookie document.cookie = "DownloadComplete=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;"; clearInterval(interval); } }, 500); } </script>
关键注意点
- 禁止使用
Response.End():它会强制终止HTTP响应,导致后续Cookie、脚本无法发送,改用Response.Close()或HttpContext.Current.ApplicationInstance.CompleteRequest()。 - 同步下载场景下,页面不会刷新,后端注册的脚本无法执行,必须通过前端主动检测(Cookie/AJAX回调)控制加载器状态。
内容的提问来源于stack exchange,提问作者Nadeem
相关产品推荐
相关产品推荐

