SqlFileStream:在 HTTP 响应中返回流与字节数组

SqlFileStream: Returning stream vs byte array in HTTP response

我对 return 使用 .net Web API.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: 为什么他们 return HTTP 响应中的流而不是字节数组?

问题 2: 如果通过调用 (byte[])reader["Context"] 字节数组已经可用,为什么还要创建一个 SqlFileStream 来读取数据?这不是意味着整个文件内容都被读入内存了吗?那么为什么需要 Stream?

缓冲 是 returning StreamContent 的主要原因。在 ASP.NET Web API 中,每次您 return 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")
        };

Question 1: Why would they return a Stream instead of a byte array in the HTTP Response?

因为字节数组可能会很大,所以如果你把整个数组读入服务器的内存中,一直保存在内存中,直到全部传给客户端,这样会给服务器带来巨大的内存负担.这就是拒绝服务攻击的组成部分。通过使用流,您允许服务器根据需要以小块的形式加载数据,并在任何给定时间只在内存中保留一小块数据,同时等待数据被传输。

Question 2: Why create a SqlFileStream to read the data if the byte array is already available by calling (byte[])reader["Context"]? Wouldn't this mean that the entire file contents are read into memory? So why the need for a Stream?

您看到的字节数组不是实际文件内容。如果你看一下 the documentation of the constructor of SqlFileStream, and also at the documentation of the SqlFileStream class,这个字节数组是一些 "transaction context",这是数据库服务器从存储中读取实际数据所必需的(一个可怕的 hack)。实际数据可能很大,因此您发布的代码会执行所有这些操作以避免将其全部加载到内存中。