对于使用.netWebneneneba API在HTTP响应中返回字节数组与流的问题,我有点困惑。
我遇到了以下代码:
SqlConnection conn = new SqlConnection();
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = "Select FileData.PathName() As FilePath, GET_FILESTREAM_TRANSACTION_CONTEXT() AS Context From FileStorage";
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
reader.Read();
string filePath = (string)reader["FilePath"];
byte[] fileBytes = (byte[])reader["Context"];
SqlFileStream stream = new SqlFileStream(filePath, fileBytes, FileAccess.Read);
result.Content = new StreamContent(stream);
result.Content.Headers.ContentType = new MediaTypeHeaderValue("application/octet-stream");
result.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment");
问题1:为什么他们会在HTTP响应中返回Stream而不是字节数组?
问题2:如果字节数组已通过调用(byte[])reader["Context"]
可用,为什么要创建SqlFileStream来读取数据?这难道不意味着整个文件内容都被读取到内存中吗?那么为什么需要一条溪流呢?
问题1:为什么他们会在HTTP响应中返回Stream而不是字节数组?
因为字节数组可能很大,所以如果将整个数组读取到服务器的内存中,并将其保留在内存中,直到将其全部传输到客户端,则会给服务器带来巨大的内存负担。这就是拒绝服务攻击的组成部分。通过使用流,服务器可以根据需要以小块的形式加载数据,并在任何给定时间只在内存中保留一小块,同时等待数据传输。
问题2:如果字节数组已经通过调用(byte[])reader["Context"]可用,为什么要创建SqlFileStream来读取数据?这难道不意味着整个文件内容都被读取到内存中吗?那么为什么需要一条溪流呢?
您看到的字节数组是,而不是实际的文件内容。如果你看看SqlFileStream
构造函数的文档,以及SqlFileStream
类的文档,这个字节数组是一些"事务上下文",这是数据库服务器从存储中读取实际数据所必需的(一个可怕的破解)。实际数据可能是巨大的,所以您发布的代码会执行所有这些操作,以避免将其全部加载到内存中。
缓冲是返回StreamContent的主要原因。在ASP.NET Web API中,每次返回StreamContent时,响应都不会被缓冲,但字节数组响应已经被缓冲并可供使用。在byte[]的情况下,HttpResponseMessage的内容可以直接从byte[]设置,并且不需要将其转换为Stream类型。此外,考虑在您希望将二进制内容连续流式传输到客户端的场景中使用PushStreamContent,以便客户端可以在数据到达时逐渐消耗您的api,类似于以下代码狙击:
var httpResponseMessage = new HttpResponseMessage
{
Content = new PushStreamContent(async (respStream, content, context) =>
{
using (var writer = new StreamWriter(respStream))
{
await writer.WriteLineAsync();
await writer.FlushAsync();
}
}, "text/plain")
};