【问题标题】:asp.net Core 1.1 chunked responsesasp.net Core 1.1 分块响应
【发布时间】:2017-03-10 16:13:38
【问题描述】:

希望有人能在以下方面启发我。

我有一个客户端将向控制器端点发出请求(没有视图,c# 到 c# 甚至 C++ 之后)。该控制器必须发送响应,因为它以 json 的形式异步获取它们(将 json1 发送到客户端,然后是 json2,然后是 json3,直到它关闭连接或发送空终止文本或类似内容)。目的是将结果流式传输回客户端,以便在服务器仍在工作时开始处理。

我的控制器端点如下所示:

        [HttpGet("testStream")]
        public async Task testStream()
        {
            var response = HttpContext.Response;
            response.Headers[HeaderNames.TransferEncoding] = "chunked";


            for (var i = 0; i < 10; ++i)
            {
                await response.WriteAsync($"6\r\ntest {i}\r\n");

                await response.Body.FlushAsync();
                await Task.Delay(1 * 1000);
            }
            await response.WriteAsync("0\r\n\r\n");
            await response.Body.FlushAsync();
        }

我的测试如下所示:

        static async void DownloadPageAsync()
        {
            // ... Target page.
            string page = "http://localhost:8080/api/Stream/testStream";
            Console.WriteLine("test");
            while (!Debugger.IsAttached) Thread.Sleep(500);
            // ... Use HttpClient.
            using (HttpClient client = new HttpClient())
            using (var response = await client.GetAsync(page, HttpCompletionOption.ResponseHeadersRead))
            using (HttpContent content = response.Content)
            {
                string result = await content.ReadAsStringAsync();
                do
                {
                    Console.WriteLine(result);
                    result = await content.ReadAsStringAsync();
                }
                while (result != "null");
            }
            Console.WriteLine("END");
        }
        [Fact]
        public void Test1()
        {
            TestSurvey.DownloadPageAsync();
        }

当我打电话给content.ReadAsStringAsync();时遇到异常

System.Net.Http.HttpRequestException : Error while copying content to a stream.
[xUnit.net 00:01:14.5836121]       ---- System.IO.IOException : The read operation failed, see inner exception.
[xUnit.net 00:01:14.5836496]       -------- System.Net.Http.CurlException : Failure when receiving data from the peer
[xUnit.net 00:01:14.5846837]       Stack Trace:
[xUnit.net 00:01:14.5857807]            at System.Net.Http.HttpContent.<LoadIntoBufferAsyncCore>d__48.MoveNext()

编辑:异常是由于未发送块的大小 await response.WriteAsync($"6\r\ntest {i}\r\n");

但现在在测试/客户端,我一次得到所有的块......

【问题讨论】:

  • 你为什么让你的代码效率降低await Task.Delay(1 * 1000);
  • 基本上,不要这样做。只需将数据发送回去。 HTTP will chunk 如果需要的话。您在这里所做的一切都是在减慢您的服务速度而不是加快它的速度。
  • 这是为了测试目的,我希望看到答案慢慢回来......
  • 我已编辑代码以在您的链接中使用分块原则(先发送尺寸,然后发送文本)。但在客户端,我一口气收到了所有信息。
  • 将会发生什么。传输是分块的。它通过 HTTP 分块发送。客户端将在之前等待所有块到达。分块用于防止 HTTP 数据包变得太大,它不是异步通信方法。您想在这里实现什么目标?

标签: c# asp.net-core asp.net-core-mvc .net-core


【解决方案1】:

为了解决这个问题,我使用了 SSE 或服务器端事件。 这是asp.net核心中的服务器端:

        [HttpGet("testStream")]
        public async Task testStream()
        {
            var response = HttpContext.Response;
            response.StatusCode = 200;
            response.ContentType = "text/event-stream";

            for (var i = 0; i < 10; ++i)
            {
                //the tags are either 'events:' or 'data:' and two \n indicates ends of the msg
                //event: xyz \n\n
                //data: xyz \n\n
                await response.WriteAsync($"data: test {i}\n\n");

                response.Body.Flush();
                await Task.Delay(5 * 1000);
            }
            await response.WriteAsync("data:\n\n");
            await response.Body.FlushAsync();
        }

这里是客户端:

        string page = "http://localhost:8080/api/Stream/testStream";

        //while (!Debugger.IsAttached) Thread.Sleep(500);

        using (HttpClient client = new HttpClient())
        using (var s = await client.GetStreamAsync(page))
        {
            using (StreamReader r = new StreamReader(s))
            {
                string line = null;
                while (null != (line = r.ReadLine()))
                {
                    Console.WriteLine(line);
                }
            }
        }

使用 ReadAsStringAsync 强制等待所有消息以继续。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-13
    • 1970-01-01
    • 1970-01-01
    • 2017-07-17
    • 2011-05-09
    • 1970-01-01
    • 2017-10-11
    • 2017-03-31
    相关资源
    最近更新 更多