You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AJAX页面文件下载完成前被提前删除的问题及解决方案咨询

问题场景

我有一个AJAX页面,用户点击按钮后要执行文件解密→下载→删除解密文件的流程,但目前间歇性出现解密文件在下载完成前就被删除的情况,导致文件部分下载或完全无法下载。原本的服务器端直接下载方法在AJAX页面无法生效,所以采用了客户端与服务器端交互的方式实现,相关代码见下文,想咨询如何避免文件提前删除,或者有没有更简洁的实现方式。

原实现代码

VB.NET服务端DownloadFile方法

Sub DownloadFile()
    output = MapPath + _hdnFilePath.Value
    input = output.Replace("_dec", "_enc")
    crptFile.Decrypt(input, output)
    Dim encodedFileName As String = _hdnFilePath.Value.Replace("'", "@@@")
    RadAjaxManager1.ResponseScripts.Add("downloadURI('" & encodedFileName & "');")
    ''OLD  DOWNLOAD METHOD BELOW - does not work with ajax
    'Response.Clear()
    'Response.ContentType = "application/pdf"
    'Response.AppendHeader("Content-Disposition", "attachment; filename=" + 
    'Path.GetFileName(output))
    'Response.WriteFile(output)
    'Response.Flush()

    'Delete the decrypted (output) file.
    'File.Delete(output)
End Sub

Javascript客户端downloadURI函数

function downloadURI(encodedFileName) {
    encodedFileName = encodedFileName.replace(/\@\@\@/g, "'");
    var encodedURI = encodeURIComponent(encodedFileName)
    encodedFileName = encodedFileName.replace("###", "%").replace("$$$", "&")
    fetch('<%= ResolveUrl("/CUTracking/CUFiles/") %>' + encodedURI)
        .then(resp => resp.blob())
        .then(blob => {
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = encodedFileName;
            document.body.appendChild(a);
            a.click();
            window.URL.revokeObjectURL(url);
            a.remove();
        })
        .catch(() => alert('There was an error'));
    $find("<%= RadAjaxManager1.ClientID %>").ajaxRequest("Delete")
}

VB.NET服务端删除方法

Protected Sub RadAjaxManager1_AjaxRequest(sender As Object, e As 
    AjaxRequestEventArgs)
    If e.Argument = "Delete" Then
        File.Delete(MapPath + _hdnFilePath.Value)
    End If
End Sub
解决方案

1. 修复文件提前删除的问题

核心问题是当前代码中,ajaxRequest("Delete")在fetch发起后立即执行,没有等待下载完成。需要把删除请求放在下载完成的回调逻辑里,确保客户端成功获取并处理完文件后,再通知服务器删除文件。

修改后的Javascript代码:

function downloadURI(encodedFileName) {
    encodedFileName = encodedFileName.replace(/\@\@\@/g, "'");
    var encodedURI = encodeURIComponent(encodedFileName)
    encodedFileName = encodedFileName.replace("###", "%").replace("$$$", "&")
    fetch('<%= ResolveUrl("/CUTracking/CUFiles/") %>' + encodedURI)
        .then(resp => resp.blob())
        .then(blob => {
            const url = window.URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.style.display = 'none';
            a.href = url;
            a.download = encodedFileName;
            document.body.appendChild(a);
            a.click();

            // 统一处理下载完成/失败后的清理与删除请求
            const handleCleanup = () => {
                window.URL.revokeObjectURL(url);
                a.remove();
                $find("<%= RadAjaxManager1.ClientID %>").ajaxRequest("Delete");
            };

            // 监听下载相关事件,兼容不同浏览器
            a.addEventListener('load', handleCleanup);
            a.addEventListener('error', handleCleanup);
            // 兜底超时:避免部分浏览器不触发事件的情况
            setTimeout(handleCleanup, 3000);
        })
        .catch(err => {
            alert('There was an error');
            // 下载失败也清理文件,避免残留
            $find("<%= RadAjaxManager1.ClientID %>").ajaxRequest("Delete");
        });
}

2. 更简洁的实现方式(消除时序问题)

可以让服务器直接返回解密后的文件流,同时在响应结束后自动删除文件,不需要客户端额外发起删除请求,彻底避免时序问题。

修改后的VB.NET服务端方法

Sub DownloadFile()
    output = MapPath + _hdnFilePath.Value
    input = output.Replace("_dec", "_enc")
    crptFile.Decrypt(input, output)

    Try
        ' 直接输出文件流到响应
        Response.Clear()
        Response.ContentType = "application/pdf"
        Response.AppendHeader("Content-Disposition", "attachment; filename=" + Path.GetFileName(output))
        Response.WriteFile(output)
        Response.Flush()
        Response.End()
    Finally
        ' 无论响应是否成功,都删除解密后的文件
        If File.Exists(output) Then
            File.Delete(output)
        End If
    End Try
End Sub

客户端调用调整

不需要downloadURI函数,通过创建隐藏表单发起同步请求即可适配AJAX环境:

function triggerDownload() {
    const form = document.createElement('form');
    form.method = 'POST';
    form.action = '<%= ResolveUrl("YourPage.aspx/DownloadFile") %>';
    
    // 传递文件路径参数
    const pathInput = document.createElement('input');
    pathInput.type = 'hidden';
    pathInput.name = 'hdnFilePath';
    pathInput.value = '<%= _hdnFilePath.Value %>';
    form.appendChild(pathInput);

    document.body.appendChild(form);
    form.submit();
    form.remove();
}

这种方式的优势:

  • 无需客户端额外的删除请求,服务器端自动清理文件
  • 彻底消除前后端时序问题,不会出现文件提前删除的情况
  • 代码更简洁,减少了前后端交互环节

内容的提问来源于stack exchange,提问作者rgorr

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 05:21:15