/// <summary>
/// 文件中转下载
/// </summary>
/// <param name="FilePath">文件相对路径</param>
/// <returns></returns>
[HttpGet]
public void DownloadFile1([FromQuery] string FilePath)
{
try
{
string filePath = GlobalConfig.Com.WebPath.UserResourcePath + FilePath; //文件物理路径
if (!System.IO.File.Exists(filePath))
{
LogHelper.Info($"客户端下载文件失败:文件不存在,文件绝对路径:{filePath}", LogHelper.GetCurSourceFileName(), LogHelper.GetLineNum());
return;
}
string fileName = Path.GetFileName(filePath);
long beginPosition = 0;
var fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, true);
//断点续传
string rangeStr = Request.Headers["range"]; //range 参数格式:byte=1024-,这个是http协议的格式,也可以自定义格式
if (!string.IsNullOrEmpty(rangeStr)) //断点续传
{
string byteStr = rangeStr.Split("=")?[1];
if (!string.IsNullOrEmpty(byteStr))
{
var byteArr = byteStr.Split("-");
if (byteArr != null && byteArr.Length > 1)
{
beginPosition = Convert.ToInt64(byteArr[0]);
}
}
}
HttpContext.Response.ContentType = "application/octet-stream";
HttpContext.Response.Headers.Append("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName));
HttpContext.Response.Headers.Append("Charset", "utf-8");
HttpContext.Response.Headers.Append("Access-Control-Expose-Headers", "Content-Disposition");
int bufferSize = 1024; //每次读取1MB到服务器内存
using (HttpContext.Response.Body)
{
long contentLength = fs.Length;
HttpContext.Response.ContentLength = contentLength;
byte[] buffer;
long hasRead = 0;
while (hasRead < contentLength)
{
if (HttpContext.RequestAborted.IsCancellationRequested)
{
//取消下载会进来,这里可以做一些操作。。。。。
break;
}
fs.Seek(hasRead, SeekOrigin.Begin);
buffer = new byte[bufferSize];
//从下载文件中读取bufferSize(1024字节)大小的内容到服务器内存中
int currentRead = fs.Read(buffer, 0, bufferSize);
HttpContext.Response.Body.WriteAsync(buffer, 0, currentRead);
HttpContext.Response.Body.Flush();
hasRead += currentRead;
}
if (hasRead == contentLength) //下载完成
{
//下载完成之后要做的事。。。。
return;
}
}
}
catch (Exception ex)
{
LogHelper.Error("客户端下载文件出现异常:", ex, LogHelper.GetCurSourceFileName(), LogHelper.GetLineNum());
return;
}
}
文件下载:这里使用的是同步方法,在本地测试和Linux下命令行启动项目,都是没问题的,等整个文件下载完成才会往下走,但是在nginx代理下,就会出现异步情况:文件下载一部分,就走到下面了,不理解。。。。。
注释:至于为什么要用同步方法,是因为我们的需求是:下载文件之后需要扣除平台的流量(充值获得)。。。。。
建议试试 Response.Body 的 CopyTo 方法
using (var fs = new FileStream(filepath, FileMode.Open))
{
HttpContext.Response.Body.CopyTo(fs);
}
另外,FileStream 没有 Dispose 是个隐患
var fs = new FileStream(filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite, 4096, true);
问题可能是 HttpContext.Response.Body.Flush();
引起的,建议将之移动到 while 循环的外面
@dudu: 还是没能解决这个问题,就是我的文件还在下载的时候,就已经到了下面了
@汪小让: 建议去掉 using (HttpContext.Response.Body)
这个地方的 using
可能是某个nginx参数超限制导致请求中断了,检查一下nginx转发的内容大小限制、请求超时看看,先试着把参数调大看看。
启用Kestrel详细日志,观察请求 ConnectionId 是否有变化