ASP.NET响应流写入的一些问题

26

我正在使用ASP.NET HttpHandler进行测试,以便直接在响应流上编写下载文件,并且我对自己的做法并不确定。 下面是一个示例方法,在将来,该文件可能会存储在数据库中的BLOB中:

        public void GetFile(HttpResponse response)
    {
        String fileName = "example.iso";
        response.ClearHeaders();
        response.ClearContent();
        response.ContentType = "application/octet-stream";
        response.AppendHeader("Content-Disposition", "attachment; filename=" + fileName);
        using (FileStream fs = new FileStream(Path.Combine(HttpContext.Current.Server.MapPath("~/App_Data"), fileName), FileMode.Open))
        {
            Byte[] buffer = new Byte[4096];
            Int32 readed = 0;

            while ((readed = fs.Read(buffer, 0, buffer.Length)) > 0)
            {
                response.OutputStream.Write(buffer, 0, readed);
                response.Flush();
            }
        }
    }

但是我不确定这是否正确或者是否有更好的方法可以实现。

我的问题是:

  1. 当我用浏览器打开URL时,会出现“保存文件”对话框...但似乎服务器在我点击“保存”之前已经开始向流中推送数据了,这正常吗?
  2. 如果我删除“response.Flush()”这一行,当我用浏览器打开URL时,...我看到Web服务器正在推送数据,但“保存文件”对话框没有弹出(或者至少没有按照合理的时间出现),为什么?
  3. 当我使用WebRequest对象打开URL时,我发现HttpResponse.ContentLength为“-1”,尽管我可以读取流并获取文件。-1的意义是什么?什么时候HttpResponse.ContentLength将显示响应的长度?例如,我有一个检索大型XML压缩为二进制流的方法,但在这种情况下...当我使用WebRequest访问它时,在HttpResponse中我实际上可以看到ContentLength与流的长度相同,为什么?
  4. 作为用于Web服务器性能最佳的缓冲区的Byte[]数组的最优长度是多少?我读过介于4K和8K之间...但是我应该考虑哪些因素以做出正确的决策?
  5. 此方法是否会增加IIS或客户端内存使用的膨胀?或者它是否实际上正确地缓冲传输?

抱歉问了这么多问题,我在Web开发方面还是很新手:P

干杯。


1
你还应该看一下这里的样板HttpHandler实现(http://haacked.com/archive/2005/03/17/AnAbstractBoilerplateHttpHandler.aspx)和这里(http://www.hanselman.com/blog/PermaLink,guid,5c59d662-b250-4eb2-96e4-f274295bd52e.aspx)。 - Roman
你的学习方式很值得肯定。继续加油! - Joe.wang
这个会起作用:https://dev59.com/zHA75IYBdhLWcg3wUHOQ - Altaf Patel
3个回答

17
  1. 是的,这很正常。
  2. 如果你从不刷新,浏览器直到服务器完成响应(甚至没有Content-Disposition头)都不会收到任何响应。因此,它不知道显示文件对话框。
  3. Content-Length头只有在整个响应被缓冲(如果你从不刷新),或者你自己设置它时才会被设置。在这种情况下,你可以并且应该自己设置它;写入

    response.AppendHeader("Content-Length", new FileInfo(path).Length.ToString());
    
  4. 我推荐4K; 我没有任何硬性依据支持我的推荐。
  5. 这种方法是最佳的做法。通过在循环内调用Flush,你可以立即将响应发送到网络,没有任何缓冲。但是,为了获得更好的性能,你可以使用GZIP压缩。

谢谢大家,你们解决了我所有的疑惑。我很高兴能加入这个社区 :D - vtortola

2
  1. 是的,正在缓冲。
  2. Flush会将缓存的内容推送到浏览器。如果从未推送,则不会出现保存对话框。
  3. 没有看到您使用的确切文件/ URL /流,很难判断。
  4. 我认为因素取决于页面有多慢。您在4k方面会获得更好的性能。也许,较低的值将更适合适应较慢的连接。
  5. 参见#1和#2。

谢谢大家,你们解决了我所有的疑惑。很高兴能加入这个社区:D - vtortola

2

对于第三个问题,您需要在http响应中设置content-length头。其中许多值来自http标头。

我相信您可以通过将响应对象上的缓冲属性更改为false来更改缓冲。我已经有一段时间没有这样做了,所以我不记得它可能是什么。


谢谢大家,你们解决了我所有的疑问。我很高兴加入这个社区 :D - vtortola

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接