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请求一样使用fetch
或XMLHttpRequest
接收分块数据,并逐步处理每个数据块。
<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 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步