This is 迷恋自留地.|

今晚打老虎!

园龄:5年1个月粉丝:39关注:9

AspNetCore 实战:三种流式响应机制详解

在现代Web应用中,实时数据传输和高效的数据流处理变得越来越重要。AspNetCore 提供了多种流式响应机制,以满足不同场景下的需求。

在使用ChatGpt,deepseek的适合有没有想过ai的逐字显示回答是怎么实现的,下面将介绍三种主要的流式响应来实现此功能。

Server-Sent Events (SSE)

Server-Sent Events (SSE) 是一种允许服务器主动向客户端推送数据的机制,适用于实时更新的应用(如聊天应用、实时监控、新闻推送等)。

通过设置Content-Type: text/event-stream来使用SSE协议,客户端就能实时接收服务器发送的消息。

服务器端:

using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace StreamedResponseExample.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StreamController : ControllerBase
    {
        [HttpGet("sse")]
        public async Task StreamSse()
        {
            Response.ContentType = "text/event-stream";
            Response.Headers.Add("Cache-Control", "no-cache");
            Response.Headers.Add("Connection", "keep-alive");

            var messages = new string[] { 
                "Hello, ", 
                "this is an SSE message!", 
                "Here's another message." 
            };

            foreach (var message in messages)
            {
                await Response.WriteAsync($"data: {message}\n\n");
                await Response.Body.FlushAsync();  // 强制立即发送
                await Task.Delay(1000);  // 每条消息间隔1秒
            }
        }
    }
}

客户端-html:

<div id="messages"></div>

  <script>
    // 创建SSE连接
    const eventSource = new EventSource('https://localhost:7148/WeatherForecast/sse');

    // 监听消息事件
    eventSource.onmessage = function (event) {
      const messageContainer = document.getElementById('messages');
      const newMessage = document.createElement('p');
      newMessage.textContent = event.data;
      messageContainer.appendChild(newMessage);

      // 滚动到最新消息
      messageContainer.scrollTop = messageContainer.scrollHeight;
    };

    // 监听打开连接事件
    eventSource.onopen = function () {
      console.log("连接已打开");
    };

    // 监听错误事件
    eventSource.onerror = function (error) {
      console.error("发生错误", error);
      eventSource.close(); // 关闭连接
    };
  </script>

说明:

  • Response.ContentType = "text/event-stream":设置响应的类型为SSE。
  • 通过 data: {message}\n\n 格式发送消息,每次都以“data:”开头。
  • 使用EventSource API在客户端接收事件流。

SSE是一种轻量级且简单的流式响应方式,尤其适用于向客户端推送消息的场景,如实时数据更新。

WebSocket

WebSocket 是一种全双工通信协议,适用于需要双向实时通信的应用,如在线聊天、多人游戏等。优势在于可以同时接收和发送消息,且没有HTTP请求/响应的开销。

通过WebSocket,客户端和服务器之间建立持久连接,双向传输消息。

使用WebSocket进行流式传输服务器端:

using Microsoft.AspNetCore.SignalR;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace StreamedResponseExample.Controllers
{
    public class ChatHub : Hub
    {
        public async Task SendMessage(string message)
        {
            await Clients.All.SendAsync("ReceiveMessage", message);
        }
    }

    [Route("api/[controller]")]
    [ApiController]
    public class StreamController : ControllerBase
    {
        private readonly IHubContext<ChatHub> _hubContext;

        public StreamController(IHubContext<ChatHub> hubContext)
        {
            _hubContext = hubContext;
        }

        [HttpGet("websocket")]
        public async Task WebSocketStream()
        {
            var messages = new string[] { 
                "Hello, ", 
                "this is a WebSocket message!", 
                "Here's another one." 
            };

            foreach (var message in messages)
            {
                await _hubContext.Clients.All.SendAsync("ReceiveMessage", message);
                await Task.Delay(1000);  // 每条消息间隔1秒
            }
        }
    }
}

客户端:

const connection = new signalR.HubConnectionBuilder()
    .withUrl("/chatHub")
    .build();

connection.on("ReceiveMessage", function (message) {
    console.log("Received message: ", message);
});

connection.start().catch(function (err) {
    return console.error(err.toString());
});
  • WebSocket的优点在于能够进行实时的双向通信,适用于需要交互的场景。
  • 使用SignalR库可以简化WebSocket的实现,SignalR封装了WebSocket等协议,提供了更易用的API。

Chunked Transfer Encoding (分块传输编码)

分块传输编码是HTTP/1.1的一种机制,它允许服务器以多个“块”的形式将响应数据发送给客户端。客户端接收到每个块后可以立即处理,而不是等待所有数据传输完成。

ASP.NET Core默认支持分块传输编码,当响应体的内容未知时,分块传输会自动启用。

使用分块传输编码(Chunked Encoding)服务器端:

using Microsoft.AspNetCore.Mvc;
using System.Text;
using System.Threading.Tasks;

namespace StreamedResponseExample.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class StreamController : ControllerBase
    {
        [HttpGet("chunked")]
        public async Task ChunkedResponse()
        {
            Response.ContentType = "text/plain";
            var phrases = new string[] { 
                "This is ", 
                "a chunked ", 
                "response! ", 
                "Enjoy it." 
            };

            foreach (var phrase in phrases)
            {
                byte[] buffer = Encoding.UTF8.GetBytes(phrase);
                await Response.Body.WriteAsync(buffer, 0, buffer.Length);
                await Response.Body.FlushAsync();  // 强制发送数据块
                await Task.Delay(1000);  // 每块之间的延时
            }
        }
    }
}

客户端:
客户端可以像普通HTTP请求一样使用fetchXMLHttpRequest接收分块数据,并逐步处理每个数据块。

<body>
  <div id="content"></div>
  <script>
    fetch('https://localhost:7128/WeatherForecast/ChunkedResponse/chunked')
      .then(response => {
        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        const contentDiv = document.getElementById('content');

        function readChunk () {
          reader.read().then(({ done, value }) => {
            if (done) return;
            contentDiv.innerHTML += decoder.decode(value, { stream: true }) + '<br>';
            readChunk();  // 继续读取下一个数据块
          });
        }

        readChunk();
      });
  </script>
</body>

说明:

  • 分块传输编码:这是HTTP协议中的一个标准机制。它可以在响应数据还没有完全生成时就开始传输,这样客户端可以逐步接收并处理数据。

结论:

  • SSE:适合服务器向客户端推送数据(单向流)专门用于事件推送。
  • WebSocket:适合需要双向实时通信的应用。
  • 分块传输编码:适合大数据流的分块传输,支持逐步发送响应。

本文作者:今晚打老虎!

本文链接:https://www.cnblogs.com/netcore5/p/18709401

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   今晚打老虎!  阅读(67)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起