如何在ASP.NET响应中传递大文件?
我不寻找任何替代的流式文件内容从 数据库,确实我在寻找问题的根源,这是 运行文件直到IIS6,我们在经典模式下运行我们的应用程序,现在我们 将IIS升级到7,我们正在管道模式下运行应用程序池,并且 这个问题开始了 我有一个处理程序,在那里我必须按照客户的要求交付大文件。我面临以下问题如何在ASP.NET响应中传递大文件?,asp.net,iis,download,Asp.net,Iis,Download,我不寻找任何替代的流式文件内容从 数据库,确实我在寻找问题的根源,这是 运行文件直到IIS6,我们在经典模式下运行我们的应用程序,现在我们 将IIS升级到7,我们正在管道模式下运行应用程序池,并且 这个问题开始了 我有一个处理程序,在那里我必须按照客户的要求交付大文件。我面临以下问题 文件的平均大小为4到100 MB,所以让我们考虑80MB文件下载情况。 缓冲打开,慢速启动 Response.BufferOutput = True; 这导致文件启动非常缓慢,因为用户下载,甚至进度条直到几秒钟(
文件的平均大小为4到100 MB,所以让我们考虑80MB文件下载情况。 缓冲打开,慢速启动
Response.BufferOutput = True;
这导致文件启动非常缓慢,因为用户下载,甚至进度条直到几秒钟(通常为3到20秒)才会出现,原因是,IIS首先读取整个文件,确定内容长度,然后开始文件传输。文件在视频播放器中播放,运行速度非常慢,但iPad只下载了部分文件,所以运行速度很快
缓冲关闭、无内容长度、快速启动、无进度
Reponse.BufferOutput = False;
这会导致立即启动,但终端客户端(典型的浏览器,如Chrome)不知道内容长度,因为IIS也不知道,所以它不会显示进度,而是显示下载的xKB
缓冲关闭、手动内容长度、快速启动、进度和协议冲突
Response.BufferOutput = False;
Response.AddHeader("Content-Length", file.Length);
这将导致在Chrome等中立即正确下载文件,但在某些情况下,IIS处理程序会导致“远程客户端关闭连接”错误(这是非常常见的),而其他WebClient会导致协议冲突这发生在所有请求的5%到10%,而不是每个请求。
我想现在发生的是,当我们不进行缓冲时,IIS不会发送任何名为100 continue的内容,客户端可能会断开连接,而不希望有任何输出。然而,从源代码读取文件可能需要更长的时间,但在客户端,我增加了超时时间,但似乎IIS超时,无法控制
我是否可以强制响应发送100继续,而不让任何人关闭连接
更新
我在Firefox/Chrome中发现了以下标题,对于违反协议或错误的标题,这里似乎没有什么不寻常的
Access-Control-Allow-Headers:*
Access-Control-Allow-Methods:POST, GET, OPTIONS
Access-Control-Allow-Origin:*
Access-Control-Max-Age:1728000
Cache-Control:private
Content-Disposition:attachment; filename="24.jpg"
Content-Length:22355
Content-Type:image/pjpeg
Date:Wed, 07 Mar 2012 13:40:26 GMT
Server:Microsoft-IIS/7.5
X-AspNet-Version:4.0.30319
X-Powered-By:ASP.NET
更新2
转向回收仍然没有提供太多,但我已经将我的MaxWorkerProcess增加到8,现在我得到的错误数量比以前少
但平均而言,在一秒钟内的200个请求中,有2到10个请求失败,而且几乎每隔一秒钟就会发生这种情况
更新3
“服务器违反协议。Section=ResponseStatusLine”继续导致5%的请求失败,我有另一个程序从使用WebClient的Web服务器下载内容,每秒出现4-5次此错误,平均有5%的请求失败。是否仍有跟踪WebClient故障的方法
问题重新定义
接收到零字节文件
IIS出于某种原因关闭了连接,在客户端的WebConfig中,我接收到文件的0字节,而不是零字节,我们执行SHA1哈希检查,这告诉我们,在IIS web服务器中,没有记录任何错误
这是我的错误,它在我们使用实体框架时得到了解决,它在读取脏行(未提交的行),因为读取不在事务范围内,将它放在事务范围内解决了这个问题
引发协议冲突异常
WebClient抛出WebException,表示“服务器违反了协议。Section=ResponseStatusLine
我知道我可以启用不安全的头解析,但这不是重点,当我的HTTP处理程序正在发送正确的头时,不知道为什么IIS会发送任何额外的内容(在firefox和chrome上检查,没有异常),这种情况只发生2%
更新4
发现sc-win32 64错误,我在某个地方读到MinBytesPerSecond的WebLimits必须从240更改为0,但一切都是一样的。但是我注意到,每当IIS记录64 sc-win32错误时,IIS都会将HTTP状态记录为200,但有一些错误。现在我无法为200启用失败的跟踪日志记录,因为这将导致大量的fil是的
通过增加MinBytesPerSecond和禁用会话,上述两个问题都得到了解决。我添加了详细的答案,总结了每一点
当您将内容长度和bufferOutput设置为false时,失败的可能原因是IIS尝试gzip您发送的文件,通过设置内容长度,IIS无法将其更改回压缩文件,并且错误开始(*) 因此,
将BufferOutput保持为false,然后对您发送的文件禁用来自iis的gzip
——或者对所有文件禁用iis gzip,然后以编程方式处理gzip部分,将您发送的文件排除在gzip之外
出于同样的原因,一些类似的问题:
(*)为什么不再次更改它?因为从您设置标题的那一刻起,您就无法将其取回,除非您已在IIS上启用此选项,并注意标题尚未全部准备好发送到浏览器
跟进
如果不是gzip,我想到的下一件事是文件被发送了,由于某种原因连接被延迟,超时并关闭了。所以你得到了“远程主机关闭了连接”
根据原因可以解决此问题:
<httpRuntime executionTimeout="43200"
if (!File.Exists(myCacheFilePath))
{
LoadMyCache(...); // saves the file to disk. don't do this if your source is already a physical file (not stored in a db for example).
}
// we suppose user-agent (browser) cache is enabled
// check appropriate If-Modified-Since header
DateTime ifModifiedSince = DateTime.MaxValue;
string ifm = context.Request.Headers["If-Modified-Since"];
if (!string.IsNullOrEmpty(ifm))
{
try
{
ifModifiedSince = DateTime.Parse(ifm, DateTimeFormatInfo.InvariantInfo);
}
catch
{
// do nothing
}
// file has not changed, just send this information but truncate milliseconds
if (ifModifiedSince == TruncateMilliseconds(File.GetLastWriteTime(myCacheFilePath)))
{
ResponseWriteNotModified(...); // HTTP 304
return;
}
}
Response.ContentType = contentType; // set your file content type here
Response.AddHeader("Last-Modified", File.GetLastWriteTimeUtc(myCacheFilePath).ToString("r", DateTimeFormatInfo.InvariantInfo)); // tell the client to cache that file
// this API uses windows lower levels directly and is not memory/cpu intensive on Windows platform to send one file. It also caches files in the kernel.
Response.TransmitFile(myCacheFilePath)
protected void PrepareResponseStream(string clientFileName, HttpContext context, long sourceStreamLength)
{
context.Response.ClearHeaders();
context.Response.Clear();
context.Response.ContentType = "application/pdf";
context.Response.AddHeader("Content-Disposition", string.Format("filename=\"{0}\"", clientFileName));
//set cachebility to private to allow IE to download it via HTTPS. Otherwise it might refuse it
//see reason for HttpCacheability.Private at http://support.microsoft.com/kb/812935
context.Response.Cache.SetCacheability(HttpCacheability.Private);
context.Response.Buffer = false;
context.Response.BufferOutput = false;
context.Response.AddHeader("Content-Length", sourceStreamLength.ToString (System.Globalization.CultureInfo.InvariantCulture));
}
protected void WriteDataToOutputStream(Stream sourceStream, long sourceStreamLength, string clientFileName, HttpContext context)
{
PrepareResponseStream(clientFileName, context, sourceStreamLength);
const int BlockSize = 4 * 1024 * 1024;
byte[] buffer = new byte[BlockSize];
int bytesRead;
Stream outStream = m_Context.Response.OutputStream;
while ((bytesRead = sourceStream.Read(buffer, 0, BlockSize)) > 0)
{
outStream.Write(buffer, 0, bytesRead);
}
outStream.Flush();
}