【发布时间】:2014-04-08 20:54:38
【问题描述】:
TL;DR:如何使用 WCF 流式传输已知大小的大文件,并且仍向最终用户(网络浏览器)显示进度 (Content-Length)?
我有一个 WCF REST 服务,它下载然后将非常大的文件 (1-20Gb) 提供给 Web 浏览器。为简化起见,将我的服务视为代理。这迫使我在绑定上设置TransferMode = Streamed 或TransferMode = StreamedResponse,否则最终客户端将不得不等待源文件下载到网络服务器,然后才能开始实际下载。此外,缓冲传输模式会杀死服务器以获取大文件(RAM 使用)。中间磁盘存储不是一种选择。来自TransferMode 手册页:
(...) 缓冲传输将整个消息保存在内存缓冲区中,直到 传输完成。
但是当将TransferMode设置为Streamed或StreamedResponse时,WCF不再向客户端返回标头Content-length,而是添加了一个新的标头Transfer-Encoding: chunked。这与分块传输上的wikipedias article 一致:
(...) 在 Content-Length 的位置使用 Transfer-Encoding HTTP 标头 标题(...)
但我总是事先知道要传输的数据的大小,而对于最终用户来说,不知道下载的大小是非常令人沮丧的。所以:
(如何)我可以将 WCF 绑定配置为使用“流式”传输模式(更具体地说,不在发送前缓冲整个消息)并且仍然使用Content-Length 标头吗?
一些线索:
This q/a 声明 http 标准不允许在同一条消息中同时使用
Transfer-Encoding和Content-length: 123456,所以我想这不是一个选项?我曾尝试在IDispatchMessage.BeforeSendReply 中使用检查器修改标头,但此时
Content-Length标头尚未删除,Transfer-Encoding尚未设置,因此“为时过早” .我后来读到分块传输编码是在 TCP 级别上,所以即使我可以,此时更改标头也可能不起作用。我尝试设置aspNetCompatibilityEnabled
="true",将wcf传输模式设置为缓冲输出(默认),然后设置System.Web.HttpContext.Current.Response.BufferOutput = false;。虽然 wcf 忽略了这一点,但消息显然已被缓冲。根据this link,这似乎是一个缺失的功能。但是在某个地方可能仍然有一个古怪的解决方法..
【问题讨论】:
标签: c# wcf http browser http-headers