SSE服务端向客户端单向推送消息
服务端
[ApiController] [Route("[controller]")] public class SseController : ControllerBase { public async Task SendEvent() { HttpContext.Response.ContentType = "text/event-stream"; HttpContext.Response.Headers["Cache-Control"]= "no-cache"; HttpContext.Response.Headers["Connection"]="no"; try { while (!HttpContext.RequestAborted.IsCancellationRequested ) { var message=new StringBuilder(); message.AppendLine("data: Hello, world!"); message.AppendLine(); //发送消息 await HttpContext.Response.WriteAsync(message.ToString()); // 写入数据到响应后不要忘记 FlushAsync(),因为该api方法是异步的,所以要全程异步,调用同步方法会报错。 await HttpContext.Response.Body.FlushAsync(); // 等待一段时间后再发送下一个消息 await Task.Delay(3000); // 检查连接是否仍然打开 if (HttpContext.Response.HasStarted && HttpContext.Response.Body.CanRead) { var buffer = new byte[256]; var result = await HttpContext.Response.Body.ReadAsync(buffer, 0, buffer.Length); if (result == 0) { // 客户端已断开连接 break; } } } }catch (Exception ex) { } } }
客户端
以VUE为例
安装包:
npm install event-source-polyfill --save
onMounted(() => { initSSE() }) function initSSE() { sse.value = SSEService.subscribeWarnMsg( instance, '/csc/rest/api/Sse/events', function (event: any) { console.log('收到新消息!!!') // var info = JSON.parse(event.data) console.log('sse:', event.data) } ) }
SSEService
import { EventSourcePolyfill } from 'event-source-polyfill' import storage from 'store' export default class SSEService { static subscribeWarnMsg(proxy: any, url: string, onmessage: any) { const token = storage.get('token') const eventSource = new EventSourcePolyfill('http://test.go.com'+url, { heartbeatTimeout: 3 * 60 * 1000, headers: { Authorization: 'Bearer ' + token, Accept: 'text/event-stream' }, withCredentials: true }) eventSource.onopen = function (e) { console.log(e, '连接刚打开时触发') // e.target.addEventListener('onmessage', function (e: any) { // console.log('心跳检测', e) // }) } eventSource.onmessage = async (event) => { onmessage(event) } eventSource.onerror = (event) => { console.error('SSE 连接出错:', event) } } }