【问题标题】:How to stop file transfer if browser is closed/upload cancelled如果浏览器关闭/上传取消,如何停止文件传输
【发布时间】:2012-01-13 22:00:25
【问题描述】:

我在 MVC3 中使用 HTML5 异步上传文件。如果我有一个大文件,比如 1GB,在上传完成 50% 后我取消上传或关闭浏览器,它仍会在目标文件夹中保存一个 500MB 的文件。

如何在控制器和客户端处理这个问题?

这是我的控制器操作:

[HttpPost]
public ActionResult Upload(object fileToUpload1)
{
    var fileName = Request.Headers["X-File-Name"];
    var fileSize = Request.Headers["X-File-Size"];
    var fileType = Request.Headers["X-File-Type"];

    Request.SaveAs("D:\\uploadimage\\" + fileName, false);

    if (fileToUpload1 == null)
    {
        return Json(true, JsonRequestBehavior.AllowGet);
    }
    else { return Json(false, JsonRequestBehavior.AllowGet); }

    // return Json(false, JsonRequestBehavior.AllowGet);
}

这里是 Javascript:

// Uploading - for Firefox, Google Chrome and Safari
xhr = new XMLHttpRequest();

// Update progress bar
xhr.upload.addEventListener("progress", uploadProgress, false);

function uploadProgress(evt) {
    if (evt.lengthComputable) {
        var percentComplete = Math.round(evt.loaded * 100 / evt.total);    

        //assign value to prgress bar Div
        var progressBar = document.getElementById("progressBar");

        progressBar.max = evt.total;
        progressBar.value = evt.loaded;
    }
}

// File load event
xhr.upload.addEventListener("load", loadSuccess, false);

function loadSuccess(evt) { 
    $(fileParentDivobj).find(".ImgDiv").find("span").html("uploaded");
    addfile(fileParentDivobj);
}

//handling error
xhr.addEventListener("error", uploadFailed, false);
xhr.addEventListener("abort", uploadCanceled, false);

function uploadFailed(evt) {
    alert("There was an error attempting to upload the file.");
}

function uploadCanceled(evt) {
    alert("The upload has been canceled by the user or the browser dropped the connection.");
}  

xhr.open("POST", "@Url.Action("Upload","Home")", true);

// Set appropriate headers
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Name", file.fileName);
xhr.setRequestHeader("X-File-Size", file.fileSize);
xhr.setRequestHeader("X-File-Type", file.type);
xhr.setRequestHeader("X-File", file);

// Send the file (doh)
xhr.send(file);

【问题讨论】:

  • 您不能将文件大小与您保存的大小进行比较,如果不是完整大小,请删除/不保存它?
  • 你不能告诉服务器 [Controller] 在以下事件中使用另一个请求出现问题并删除任何具有特定名称/大小的文件吗? 1. 车身卸载 2. 中止/取消 3. 失败/错误。您可以在警报消息之后/之前执行此操作。

标签: c# javascript asp.net-mvc-3 html file-upload


【解决方案1】:

首先,这不是应该使用任何客户端脚本解决的问题,因为我不相信您将能够在浏览器关闭时发出新请求,并且当连接中断时它肯定不会工作,因为网络问题。

所以我进行了一些挖掘,但在 asp.net 中没有发现任何可以告诉我请求连接已中断的内容。但是我们可以检查我们收到了多少数据以及我们应该收到多少数据!

public ActionResult Upload()
{
    // I like to keep all application data in App_Data, feel free to change this
    var dir = Server.MapPath("~/App_Data");
    if (!Directory.Exists(dir))
        Directory.CreateDirectory(dir);

    // extract file name from request and make sure it doesn't contain anything harmful
    var name = Path.GetFileName(Request.Headers["X-File-Name"]);
    foreach (var c in Path.GetInvalidFileNameChars())
        name.Replace(c, '-');

    // construct file path
    var path = Path.Combine(dir, name);

    // this variable will hold how much data we have received
    var written = 0;
    try
    {
        using (var output = new FileStream(path, FileMode.Create, FileAccess.Write, FileShare.None))
        {
            var buffer = new byte[0x1000];
            var read = 0;

            // while there is something to read, write it to output and increase counter
            while ((read = Request.InputStream.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, read);
                output.Flush();

                written += read;
            }
        }
    }
    finally
    {
        // once finished (or when exception was thrown) check whether we have all data from the request
        // and if not - delete the file
        if (Request.ContentLength != written)
            System.IO.File.Delete(path);
    }

    return Json(new { success = true });
}

使用 asp.net 开发服务器和谷歌浏览器测试您的客户端代码。

编辑:刚刚注意到 Chuck Savage 早些时候在 cmets 中发布了这个原则,所以向他提供道具:)

【讨论】:

【解决方案2】:

专注于请求是忘记响应的原因,它可以判断客户端是否仍然连接 (Response.IsClientConnected)。
通过简单地检查是否有要阅读的内容,您可以忽略客户端可能存在长时间(多长时间?)网络延迟的情况。
使用 Chunk 和 Lukas 方法并结合 Response.IsClientConnected 属性和您选择的线程 Sleep 以防万一没有可读取的内容但客户端仍处于连接状态。这样,如果需要,您将在不从客户端用户生成 WTF 的情况下提前退出读取循环。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-09-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    • 2013-05-02
    相关资源
    最近更新 更多