【发布时间】:2014-08-22 00:23:24
【问题描述】:
问题
这几天让我发疯。我们这里有一个过程,通过驻留在 ASP.NET Web 窗体 (.NET 4.0) 中的管理页面将记录从 csv 文件 导入 数据库 ) 项目。这个过程本身太慢了,我有责任让它更快。我首先更改了核心逻辑,这提高了性能。
但如果我上传大文件(相对较大,大约 3 MB 顶部),我必须等到上传过程完成,直到我开始导入,并且我不会返回任何进度我这样做的时候客户。这个过程本身并没有那么长,大约需要 5 到 10 秒才能完成,是的,我考虑过创建一个单独的 Task 并轮询服务器,但我认为这有点矫枉过正。
到目前为止我做了什么?
所以,为了解决这个问题,我决定在阅读时读取传入的流并导入值。我创建了一个通用处理程序(.ashx),并将以下代码放入void ProcessRequest(HttpContext context):
using (var stream = context.Request.GetBufferlessInputStream())
{
}
首先我删除标题,然后我读取流(通过StreamReader)直到我得到一个 CRLF,将行转换为我的模型对象,并继续读取 csv。当我得到 200 条左右的记录时,我将它们全部更新到数据库中。然后,我不断获得更多记录,直到我结束文件或获得 200 条记录。
这似乎奏效了,但后来,我决定也将我的回复流式传输。首先,我禁用了 BufferOutput:
context.Response.BufferOutput = false;
然后,我将这些标题添加到我的响应中:
context.Response.AddHeader("Keep-Alive", "true");
context.Response.AddHeader("Cache-Control", "no-cache");
context.Response.ContentType = "application/X-MyUpdate";
然后,将这 200 条记录发送到数据库后,我写了一个响应:
response.Write(s);
response.Flush();
s 是一个固定大小为 256 个字符的字符串。我知道 256 个字符并不总是等于 256 个字节,但我只是确定我不会在响应中写入大量文本并搞砸了。
格式如下:
| pipeline (record delimiter)
1 or 0 success or failure
; delimiter
error message (if applicable)
| pipeline (next demiliter and so on)
例子:
|0;"Invalid price on line 123"|1;|1;|0;"Invalid id on line 127"|
在客户端,这是我所拥有的(只是请求部分):
function import(){
var formData = new FormData();
var file = $('[data-id=file]')[0].files[0];
formData.append('file', file);
var xhr = new XMLHttpRequest();
var url = "/Site/Update.ashx";
xhr.onprogress = updateProgress;
xhr.open('POST', url, true);
xhr.setRequestHeader("Content-Type", "multipart/form-data");
xhr.setRequestHeader("X-File-Name", file.name);
xhr.setRequestHeader("X-File-Type", file.type);
xhr.send(formData);
}
function updateProgress(evt){
debugger;
}
发生了什么:(
- 当我调用
response.Flush时,它不会立即将数据发送到客户端。我知道客户端有缓冲,但它似乎根本不起作用,即使我发送了大量虚拟数据来绕过这个问题。 - 一段时间后,当我在
Response.Write上写太多东西时,方法会越来越慢,直到挂掉。与Response.Flush相同。我想我在这里遗漏了一些东西。 - 我创建了一个简单的网络表单项目来测试我一直在尝试做的事情。它有一个通用处理程序,它将在 10 秒内每秒返回一个数字。它实际上会更新(并不总是以 1 秒的方式更新),我可以看到正在进行的进度。
- 当我在响应中只写了几行时,它实际上显示了进度,但总是在整个过程几乎完成之后。主要问题是当我遇到错误并尝试将这些写入响应时。它们比
success字符串长,因为它们包含错误消息。
我假设如果我写Response.Flush 并不能保证 100% 到达客户那里,对吗?还是客户本身的问题?如果是客户端,为什么我调用Response.Write太多时服务器会挂掉?
编辑: 作为附录,如果我将同一段代码放入 aspx 页面,它会起作用。所以我认为这与xhr (XMLHttpRequest) 本身有关,它似乎不准备处理流数据。
如果需要,我很乐意提供更多信息。
【问题讨论】: