开发的系统有时候需要后端主动的推送数据到前端,有一些方式比如轮询,建立http长连接,websocket主动推送。下面这篇文章主要介绍利用websocket进行主动推送的实现,有人可能说用singleR,我在预研时有了解到实际封装的就是websocket,那我还不如直接用wsk,这样也不会多一层的调用,你们觉得呢!

1、首先在core项目中应用websocketserver的组件,通过nuget即可安装进入项目中,搜索安装Microsoft.AspNetCore.WebSockets.Server。

2、在项目中添加一个WebsocketHandlerMiddleware的处理类,监听客户端连接过来的请求,把连接的对象信息进行本地化add保存。

public class WebsocketHandlerMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        public WebsocketHandlerMiddleware(
            RequestDelegate next,
            ILoggerFactory loggerFactory
            )
        {
            _next = next;
            _logger = loggerFactory.
                CreateLogger<WebsocketHandlerMiddleware>();
        }

        public async Task Invoke(HttpContext context)
        {
            if (context.Request.Path == "/ws")
            {
                if (context.WebSockets.IsWebSocketRequest)
                {
                    WebSocket webSocket = await context.WebSockets.AcceptWebSocketAsync();
                    string clientId = Guid.NewGuid().ToString();  
                    var wsClient = new WebsocketClient
                    {
                        //uuId = clientId,
                        WebSocket = webSocket
                    };
                    try
                    {
                        await Handle(wsClient);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogError(ex, "Echo websocket client {0} err .", clientId);
                        await context.Response.WriteAsync("closed");
                    }
                }
                else
                {
                    context.Response.StatusCode = 404;
                }
            }
            else
            {
                await _next(context);
            }
        }

        private async Task Handle(WebsocketClient webSocket)
        { 
            WebSocketReceiveResult result = null;
            do
            {
                var buffer = new byte[1024 * 2];
                result = await webSocket.WebSocket.ReceiveAsync(new ArraySegment<byte>(buffer), CancellationToken.None);
                if (result.MessageType == WebSocketMessageType.Text && !result.CloseStatus.HasValue)
                {
                    var msgString = Encoding.UTF8.GetString(buffer);
                    _logger.LogInformation($"Websocket client ReceiveAsync message {msgString}.");
                    var message = JsonConvert.DeserializeObject<Message>(msgString);
                    webSocket.uuId = message.ClientId;   
           
                    //MessageRoute(message);

                    WebsocketClientCollection.Add(webSocket);
                    _logger.LogInformation($"Websocket client added.");

                    //SendMsgToClient();
                }
            }
            while (!result.CloseStatus.HasValue);
            WebsocketClientCollection.Remove(webSocket);
            _logger.LogInformation($"Websocket client closed.");
        }
 
        }
    }

3、在startup中添加注册 websocket 服务,当请求为"/ws"走websockt处理handler

app.UseWebSockets(new WebSocketOptions
            {
                KeepAliveInterval = TimeSpan.FromSeconds(60),
                ReceiveBufferSize = 2 * 1024
            });

            app.UseMiddleware<WebsocketHandlerMiddleware>();

4、定义一个客户端的websocket对象,管理websocket的连接对象信息等

public class WebsocketClient
    {

        public WebSocket WebSocket { get; set; }

        public string uuId { get; set; }

     
        public Task SendMessageAsync(string message)
        {
            var msg = Encoding.UTF8.GetBytes(message);
            return WebSocket.SendAsync(new ArraySegment<byte>(msg, 0, msg.Length), WebSocketMessageType.Text, true, CancellationToken.None);
        }
    }

以上基本就是后端的一些处理的主要逻辑,还有粘贴了一些主要的代码示例。一些对象信息可以根据自身项目的业务来进行补充和调整。 下面粘贴的是前端的js示例代码

var socket; //websocket的实例
var wsUrl = "ws://localhost:55565/ws";
function connectWsk() {
    
    socket = new WebSocket(wsUrl);
    socket.onopen = function (evt) {
 
        var message = {
            action: 'join',
            ClientId: $("#uuid").val(), 
        };
        sendmsgwsk(message); 
    };

    socket.onmessage = function (evt) {
        console.log('Connection success.');

        var data = JSON.parse(evt.data);

        // 处理接收的data对象

    };
    socket.onclose = function (evt) {
        console.log('Connection closed.');
        reconnect(wsUrl);
    };
    socket.onerror = function (evt) {
        console.log('websocket服务出错了');
        reconnect(wsUrl);
    };

    // 重新链接
    function reconnect(url) {
        if (lockReconnect) return;
        lockReconnect = true;
        //没连接上会一直重连,设置延迟避免请求过多
        setTimeout(function () {
            connectWsk();
            lockReconnect = false;
        }, 2000);
    }
    //心跳检测
    var heartCheck = {
        timeout: 5000, //5秒发一次心跳检测
        timeoutObj: null,
        serverTimeoutObj: null,
        reset: function () {
            clearTimeout(this.timeoutObj);
            clearTimeout(this.serverTimeoutObj);
            return this;
        },
        start: function () {
            var self = this;
            this.timeoutObj = setTimeout(function () {
                //这里发送一个心跳,后端收到后,返回一个心跳消息,
                //onmessage拿到返回的心跳就说明连接正常
                socket.send("心跳包");
                //如果超过一定时间还没重置,说明后端主动断开了
                self.serverTimeoutObj = setTimeout(function () {
                    //如果onclose会执行reconnect,我们执行ws.close()就行了.
                    //如果直接执行reconnect 会触发onclose导致重连两次
                    socket.close();
                }, self.timeout)
            }, 3000)
        }
    }
}

function closewsk() {
    if (!socket || socket.readyState != WebSocket.OPEN) { 
        console.log('socket服务出错了');
    }
    socket.close(1000, "从客户端关闭");
}

function sendmsgwsk(message) {
    if (!socket || socket.readyState != WebSocket.OPEN) { 
        console.log('socket未连接');
    }

    socket.send(JSON.stringify(message));
}

最后建议做前后端通讯时,分开两个项目进行开发。

以上就是一个前后端的主要介绍,粘贴的示例代码。希望对你的开发有所帮助!