如果浏览器关闭/上传取消,如何停止文件传输

我在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); 

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

所以我做了一些挖掘,我没有在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早先在评论中发布了这个原则,所以道具给他:)

关注请求是忘记响应的原因,该响应可以判断客户端是否仍然连接(Response.IsClientConnected)。
通过简单地检查是否有东西要读,你忽略了客户端可能长(多长?)网络延迟的情况。
使用Chunk和Lukas方法并合并Response.IsClientConnected属性和一个线程Sleep of choise,以防无法读取但客户端仍然连接。 这样,如果需要,您将提前退出读取循环,而不会从客户端用户生成WTF。