WebAPI 是否支持按块读取分块请求?
Does WebAPI support reading chunked requests by chunk?
问题
我正在尝试将一些数据上传到网络服务。
我想上传数据in chunks,并让网络服务依次读取每个块。然而,我在实践中发现,网络服务一次只会读取一个完整的缓冲区。
有没有办法让 WebAPI(运行 理想情况下由 Owin 自托管,但如果需要我可以使用 IIS)遵守传输块?
我已经在 Wireshark 中验证我的客户端正在发送分块数据,因此我认为这是一个 WebAPI 问题。
为清楚起见,响应中的流式数据绝对可以正常工作 - 我的问题是关于从请求流中读取分块数据。
代码
控制器看起来像这样:
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
public class StreamingController : ApiController
{
[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
var stream = await this.Request.Content.ReadAsStreamAsync();
var data = new byte[20];
int chunkCount = 1;
while (true)
{
// I was hoping that every time I sent a chunk, then
// ReadAsync would return, but I find that it will only
// return when I have sent 20 bytes of data.
var bytesRead = await stream.ReadAsync(data, 0, data.Length);
if (bytesRead <= 0)
{
break;
}
Console.WriteLine($"{chunkCount++}: {Encoding.UTF8.GetString(data)}");
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
我的测试客户端是这样的:
void Main()
{
var url = "http://localhost:6001/streaming/upload";
var relayRequest = (HttpWebRequest)HttpWebRequest.Create(url);
relayRequest.Method = "POST";
relayRequest.AllowWriteStreamBuffering = false;
relayRequest.AllowReadStreamBuffering = false;
relayRequest.SendChunked = true;
relayRequest.ContentType = "application/octet-stream";
var stream = relayRequest.GetRequestStream();
string nextLine;
int totalBytes = 0;
// Read a series of lines from the console and transmit them to the server.
while(!string.IsNullOrEmpty((nextLine = Console.ReadLine())))
{
var bytes = Encoding.UTF8.GetBytes(nextLine);
totalBytes += bytes.Length;
Console.WriteLine(
"CLIENT: Sending {0} bytes ({1} total)",
bytes.Length,
totalBytes);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
var response = relayRequest.GetResponse();
Console.WriteLine(response);
}
理由
我的具体动机是为 RTP 客户端编写 HTTPS 隧道。但是,这个问题在即时消息聊天应用程序的上下文中也很有意义。您不希望部分聊天消息通过,然后必须等待消息 2 才能找到消息 1 的结尾...!
Transfer-Encoding: chunked
的解码发生在距离您的控制器很远的地方。根据您的主机,它甚至可能根本不会发生在应用程序中,而是由大多数服务器插入的 http.sys
pipeline API 处理。
为了让您的应用程序甚至有机会查看此数据,您需要离开 IIS/HttpListener 并改用套接字。
感兴趣的可能是 Nowin project,它提供所有 OWIN 功能而不使用 HttpListener,而是依赖于套接字异步 API。我不太了解它,但是 可能 是在解码之前获取流的钩子......看起来很多虽然努力。
问题
我正在尝试将一些数据上传到网络服务。
我想上传数据in chunks,并让网络服务依次读取每个块。然而,我在实践中发现,网络服务一次只会读取一个完整的缓冲区。
有没有办法让 WebAPI(运行 理想情况下由 Owin 自托管,但如果需要我可以使用 IIS)遵守传输块?
我已经在 Wireshark 中验证我的客户端正在发送分块数据,因此我认为这是一个 WebAPI 问题。
为清楚起见,响应中的流式数据绝对可以正常工作 - 我的问题是关于从请求流中读取分块数据。
代码
控制器看起来像这样:
using System;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Web.Http;
public class StreamingController : ApiController
{
[HttpPost]
public async Task<HttpResponseMessage> Upload()
{
var stream = await this.Request.Content.ReadAsStreamAsync();
var data = new byte[20];
int chunkCount = 1;
while (true)
{
// I was hoping that every time I sent a chunk, then
// ReadAsync would return, but I find that it will only
// return when I have sent 20 bytes of data.
var bytesRead = await stream.ReadAsync(data, 0, data.Length);
if (bytesRead <= 0)
{
break;
}
Console.WriteLine($"{chunkCount++}: {Encoding.UTF8.GetString(data)}");
}
return new HttpResponseMessage(HttpStatusCode.OK);
}
}
我的测试客户端是这样的:
void Main()
{
var url = "http://localhost:6001/streaming/upload";
var relayRequest = (HttpWebRequest)HttpWebRequest.Create(url);
relayRequest.Method = "POST";
relayRequest.AllowWriteStreamBuffering = false;
relayRequest.AllowReadStreamBuffering = false;
relayRequest.SendChunked = true;
relayRequest.ContentType = "application/octet-stream";
var stream = relayRequest.GetRequestStream();
string nextLine;
int totalBytes = 0;
// Read a series of lines from the console and transmit them to the server.
while(!string.IsNullOrEmpty((nextLine = Console.ReadLine())))
{
var bytes = Encoding.UTF8.GetBytes(nextLine);
totalBytes += bytes.Length;
Console.WriteLine(
"CLIENT: Sending {0} bytes ({1} total)",
bytes.Length,
totalBytes);
stream.Write(bytes, 0, bytes.Length);
stream.Flush();
}
var response = relayRequest.GetResponse();
Console.WriteLine(response);
}
理由
我的具体动机是为 RTP 客户端编写 HTTPS 隧道。但是,这个问题在即时消息聊天应用程序的上下文中也很有意义。您不希望部分聊天消息通过,然后必须等待消息 2 才能找到消息 1 的结尾...!
Transfer-Encoding: chunked
的解码发生在距离您的控制器很远的地方。根据您的主机,它甚至可能根本不会发生在应用程序中,而是由大多数服务器插入的 http.sys
pipeline API 处理。
为了让您的应用程序甚至有机会查看此数据,您需要离开 IIS/HttpListener 并改用套接字。
感兴趣的可能是 Nowin project,它提供所有 OWIN 功能而不使用 HttpListener,而是依赖于套接字异步 API。我不太了解它,但是 可能 是在解码之前获取流的钩子......看起来很多虽然努力。