为什么 StreamReader.ReadToEnd 有效,而 Stream.Read 不起作用?



我正在尝试将 ASP.NET 核心控制器中的请求正文作为byte[]数组获取。这是我最初写的:

var declaredLength = (int)request.ContentLength;
byte[] fileBuffer = new byte[declaredLength];
request.Body.Read(fileBuffer, 0, declaredLength);

此代码有效,但仅适用于小请求(大约 ~20KB)。对于较大的请求,它会填满数组中的前 20,000 个左右的字节,然后数组的其余部分为空。

我在这里的顶部答案中使用了一些代码,并且在重写代码后能够成功读取整个请求正文:

var declaredLength = (int)request.ContentLength;
byte[] fileBuffer = new byte[declaredLength];
// need to enable, otherwise Seek() fails
request.EnableRewind();
// using StreamReader apparently resolves the issue
using (var reader = new StreamReader(request.Body, Encoding.UTF8, true, 1024, true))
{
reader.ReadToEnd();
}
request.Body.Seek(0, SeekOrigin.Begin);
request.Body.Read(fileBuffer, 0, declaredLength);

为什么StreamReader.ReadToEnd()能够成功读取整个请求正文,而Stream.Read()却不能?两次读取请求流感觉就像黑客一样。有没有更好的方法可以解决这个问题?(我只需要将流读入字节数组一次)

请记住,您正在尝试在收到所有请求之前阅读request.Body

Stream.Read的行为是这样的:

  1. 如果已到达流的末尾,请返回0
  2. 如果没有尚未读取的可用字节,则阻止,直到至少有 1 个字节可用
  3. 如果有 1 个或多个新字节可用,请立即返回它们。不要阻止。

如您所见,如果整个身体尚未接收,request.Body.Read(...)将只返回已接收的身体部分。

StreamReader.ReadToEnd()调用Stream.Read循环,直到找到流的末尾。

您可能也应该在循环中调用Stream.Read,直到您读取了所有字节:

byte[] fileBuffer = new byte[declaredLength];
int numBytesRead = 0;
while (numBytesRead < declaredLength)
{
int readBytes = request.Body.Read(fileBuffer, numBytesRead, declaredLength - numBytesRead);
if (readBytes == 0)
{
// We reached the end of the stream before we were expecting it
// Might want to throw an exception here?
}
numBytesRead += readBytes;
}

最新更新