在asp.net中,要向客户端提供文件下载功能,经常需要用到Response.Flush();这一句代码(您说可以不用?是的,不过对大文件的下载,不用这一行,我还没有找到合理的实现方式),但是只要有这一行代码的存在,那么当客户端点击链接弹出迅雷下载并且又点击了“取消”时,问题就出来了:服务器的asp.net进程会一直处于阻塞状态,无法再响应任何操作,直到客户端退出迅雷!
不相信的可以试一试。我也希望这只是由于某种偶然因素导致的,而不是必然现象。
大家可有什么好的解决办法?
我用于下载功能的核心代码:
#region -------添加重要响应头、解析请求头、相关验证------------------- httpContext.Response.Clear(); httpContext.Response.BufferOutput = false;//此处如果设为false,会导致迅雷打开并取消后一直阻塞asp.net进程 //httpContext.Response.AddHeader("Content-MD5", GetMD5Hash(myFile));//用于验证文件 httpContext.Response.AddHeader("Accept-Ranges", "bytes");//重要:续传必须 httpContext.Response.AppendHeader("ETag", "\"" + eTag + "\"");//重要:续传必须 httpContext.Response.AppendHeader("Last-Modified", lastUpdateTiemStr);//把最后修改日期写入响应 httpContext.Response.ContentType = "application/octet-stream";//MIME类型:匹配任意文件类型 httpContext.Response.AddHeader("Content-Disposition", "attachment;filename=" + ProcessFileName(Path.GetFileName(filePath))); httpContext.Response.AddHeader("Content-Length", (fileLength - startBytes).ToString()); httpContext.Response.AddHeader("Connection", "Keep-Alive"); httpContext.Response.ContentEncoding = Encoding.UTF8; if (httpContext.Request.Headers["Range"] != null) { //------如果是续传请求,则获取续传的起始位置,即已经下载到客户端的字节数------ httpContext.Response.StatusCode = 206;//重要:续传必须,表示局部范围响应。初始下载时默认为200 string[] range = httpContext.Request.Headers["Range"].Split(new char[] { '=', '-' });//"bytes=1474560-" startBytes = Convert.ToInt64(range[1]);//已经下载的字节数,即本次下载的开始位置 if (startBytes < 0 || startBytes >= fileLength) { //无效的起始位置 return false; } } if (startBytes > 0) { //------如果是续传请求,告诉客户端本次的开始字节数,总长度,以便客户端将续传数据追加到startBytes位置后---------- httpContext.Response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", startBytes, fileLength - 1, fileLength)); } #endregion #region -------向客户端发送数据块------------------- br.BaseStream.Seek(startBytes, SeekOrigin.Begin); int maxCount = (int)Math.Ceiling((fileLength - startBytes + 0.0) / packSize);//分块下载,剩余部分可分成的块数 for (int i = 0; i < maxCount && httpContext.Response.IsClientConnected; i++) //客户端中断连接,则暂停 { httpContext.Response.BinaryWrite(br.ReadBytes(packSize)); //考虑取消下面一行,否则导致迅雷打开并取消后一直阻塞asp.net进程 httpContext.Response.Flush(); if (sleep > 1) System.Threading.Thread.Sleep(sleep); } #endregion
一般Response.Flush()是自动调用的,只有按块传送时的最后一个块需要Response.Flush()来刷新并发送,因为没达到缓冲区大小
你的说法很有道理,我试着把块大小缩小到10KB,并且取消循环中的Response.Flush()语句,似乎并不影响大文件的下载,并且也解决了迅雷取消下载造成的进程阻塞问题。但是如果像你说的那样,对最后一个块使用Response.Flush()语句,同样会造成进程阻塞问题(迅雷取消下载的话)。
能否把你的用于下载的代码给个片段?参考学习一下。谢谢!
@戒焦戒躁:
阻塞是正常的,对方不接受数据的时候程序会一直阻塞到超时为止.你的文件大小设置有问题吧,
VS里运行没发现问题,只是点取消前迅雷发了好几次请求,最后一次才取了文件大小。。。
你下载代码中使用了Response.Flush()的?迅雷取消后你的应用程序还可以继续响应操作吗?
貌似用谷歌 火狐浏览器的时候迅雷好像不会自己启动
我想在我的程序中采用你的代码,可否将上述代码完整的发送给我一份?不胜感激。邮箱:coolmanlee@foxmail.com