SignalR在React/Go技术栈的实践

a986ae12c67b197ca4c26d3b61cc8ecd.gif

哼哧哼哧半年,优化改进了一个运维开发web平台。
本文记录SignalR在react/golang 技术栈的生产小实践。

01

背景

有个前后端分离的运维开发web平台, 后端会间隔5分钟同步一次数据,现在需要将最新一次同步的时间推送到web前端。

说到[web服务端推送],立马想到SignalR,(我头脑中一直有技术体系, 但一直没实践过。)

SignalR是微软推出的实时通信标准框架,内部封装了 websocket、服务端发送事件、长轮询, 可以算是实时通信的大杀器,传送门。

实际编码就是react写SignalR客户端,golang写SignalR服务端,盲猜有对应的轮子。

02

撸起袖子干

果然, signalr的作者David Fowler实现了node、go版本, 这位老哥是.NET技术栈如雷贯耳的大牛:

89d7508992b7a122861ea5f3109b2e2b.png

但是他的仓库很久不更了,某德国大佬在此基础上开了新github仓库[1]继续支持。

SignalR的基本交互原理:

(1) signalR提供了一组API, 用于创建从服务端到客户端的远程过程调用(RPC),这个调用的具体体现是 :从服务端.NET 代码调用位于客户端的javascript 代码。

(2) signalr提供了管理实例、连接、失连, 分组管控的API。

e635ce69a7cc82c750aa6db65b249f92.png

这里面最关键的一个概念是集线器Hub,其实也就是RPC领域常说的客户端代理。
服务端在baseUrl上建立signalr的监听地址;
客户端连接并注册receive事件;

服务端在适当时候通过hubServer向HubClients发送数据。

go服务端

(1) 添加golang pgk:go get github.com/philippseith/signalr

(2) 定义客户端集线器hub,这里要实现HubInterface接口的几个方法, 你还可以为集线器添加一些自定义方法。

package servicesimport ("github.com/philippseith/signalr"log "github.com/sirupsen/logrus""time"
)type AppHub struct{signalr.Hub
}func (h *AppHub) OnConnected(connectionID string) {// fmt.Printf("%s connected\n", connectionID)log.Infoln(connectionID," connected\n" )
}func (h *AppHub) OnDisconnected(connectionID string) {log.Infoln(connectionID," disconnected\n")
}// 客户端调用的函数, 本例不用
func (h *AppHub) Send(message string) {h.Clients().All().Send("receive", time.Now().Format("2006/01/02 15:04:05") )
}

(3) 初始化集线器, 并在特定地址监听signalr请求。

这个库将signalr监听服务抽象为独立的hubServer

shub := services.AppHub{}sHubSrv,err:= signalr.NewServer(context.TODO(),signalr.UseHub(&shub), // 这是单例hubsignalr.KeepAliveInterval(2*time.Second),signalr.Logger(kitlog.NewLogfmtLogger(os.Stderr), true))sHubSrv.MapHTTP(mux, "/realtime")

(4) 利用sHubServer在合适业务代码位置向web客户端推送数据。

if clis:= s.sHubServer.HubClients(); clis!= nil {c:= clis.All()if  c!= nil {c.Send("receive",ts.Format("2006/01/02 15:04:05"))}}

注意:上面的receive方法是后面react客户端需要监听的JavaScript事件名。

react客户端

前端菜鸡,跟着官方示例琢磨了好几天。

(1) 添加@microsoft/signalr 包

(2) 在组件挂载事件componentDidMount初始化signalr连接

实际也就是向服务端baseUrl建立HubConnection,注册receive事件,等待服务端推送。

import React from 'react';
import {JsonHubProtocol,HubConnectionState,HubConnectionBuilder,HttpTransportType,LogLevel,
} from '@microsoft/signalr';class Clock extends React.Component {constructor(props) {super(props);this.state = {message:'',hubConnection: null,};}componentDidMount() {const connection = new HubConnectionBuilder().withUrl(process.env.REACT_APP_APIBASEURL+"realtime", {}).withAutomaticReconnect().withHubProtocol(new JsonHubProtocol()).configureLogging(LogLevel.Information).build();// Note: to keep the connection open the serverTimeout should be// larger than the KeepAlive value that is set on the server// keepAliveIntervalInMilliseconds default is 15000 and we are using default// serverTimeoutInMilliseconds default is 30000 and we are using 60000 set belowconnection.serverTimeoutInMilliseconds = 60000;// re-establish the connection if connection droppedconnection.onclose(error => {console.assert(connection.state === HubConnectionState.Disconnected);console.log('Connection closed due to error. Try refreshing this page to restart the connection', error);});connection.onreconnecting(error => {console.assert(connection.state === HubConnectionState.Reconnecting);console.log('Connection lost due to error. Reconnecting.', error);});connection.onreconnected(connectionId => {console.assert(connection.state === HubConnectionState.Connected);console.log('Connection reestablished. Connected with connectionId', connectionId);});this.setState({ hubConnection: connection})this.startSignalRConnection(connection).then(()=> {if(connection.state === HubConnectionState.Connected) {connection.invoke('RequestSyncTime').then(val => {console.log("Signalr get data first time:",val);this.setState({ message:val })})}}) ;connection.on('receive', res => {console.log("SignalR get hot res:", res)this.setState({message:res});});}startSignalRConnection = async connection => {try {await connection.start();console.assert(connection.state === HubConnectionState.Connected);console.log('SignalR connection established');} catch (err) {console.assert(connection.state === HubConnectionState.Disconnected);console.error('SignalR Connection Error: ', err);setTimeout(() => this.startSignalRConnection(connection), 5000);}};render() {return (<div style={{width: '300px',float:'left',marginLeft:'10px'}} ><h4>最新同步完成时间: {this.state.message}  </h4></div>);}}export  default  Clock;

(3) 将该react组件插入到web前端页面

03

效果分析

最后的效果如图:

56835a799c443736c440708bd8ff9d9b.gif

效果分析:

(1) web客户端与服务器协商 传输方式http://localhost:9598/realtime/negotiate?negotiateVersion=1,
返回可用的传输方式和连接标识ConnectionId

{"connectionId": "hkSNQT-pGpZ9E6tuMY9rRw==","availableTransports": [{"transport": "WebSockets","transferFormats": ["Text", "Binary"]}, {"transport": "ServerSentEvents","transferFormats": ["Text"]}]
}

(2) web客户端利用上面的ConnectionId向特定的服务器地址/realtime连接,建立传输通道,默认优先websocket。

5d87a7fb7e8309ebdcf93c0527220811.png

以上网络交互,大部分会通过SignalR框架自动完成。

源码:Github Demo[2]

e9249ba8b2a79d2d06a7d340f987d84d.png

引用链接

[1] Github仓库: https://github.com/philippseith/signalr
[2] Github Demo: https://github.com/zaozaoniao/SignalR-apply-to-react-and-golang

2f9bcdc59a3ca88af6687eb50b763b40.gif

●实时通信技术大乱斗

●.NET WebSocket 核心原理初体验

●.NET gRPC核心功能初体验

●大前端快闪四:这次使用一个舒服的姿势插入HttpClient拦截器

●大前端快闪三:多环境灵活配置react

●大前端快闪二:react开发模式 一键启动多个服务

●大前端快闪:package.json文件知多少?

“赞”c1804ce877a55f90662583b326de6a47.gif“在看”15e6ee14eae97e1c222dca6d3a40c059.gif

体现态度很有必要!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296739.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UVA 1609 Foul Play 不公平竞赛 (构(luan)造(gao)+递归)

题意&#xff1a;有n支队伍&#xff08;n是2的整数幂&#xff0c;2<n<4&#xff09;&#xff0c;打淘汰赛&#xff0c;胜者进入下一轮&#xff0c;其中1号队伍能打败至少一半的队伍&#xff0c;对于它不能打败的队伍l&#xff0c;一定存在一支它能够打败的队伍w&#xff…

conversion to dalvik format failed with error 1的解决办法

android低版本工程&#xff08;如1.5&#xff09;放到高版本环境中&#xff08;如2.2&#xff09;可能会上述错误&#xff0c;解决方法如下&#xff1a; 1。 如果不修改android sdk版本&#xff0c;则使用project clean 命令作用于某工程即可。 &#xff08;该处理方式…

16张扎心漫画,戳中女生私密日常,每一幕都很真实

全世界只有3.14 % 的人关注了爆炸吧知识比利时的插画师Planet Prudence&#xff0c;画了很多女生的真实日常&#xff0c;每一幕都很戳心&#xff0c;一起来看看吧。别人的痘痘一长就是一个&#xff0c;我一长就是一片。买买买的时候爽得要命&#xff0c;要穿的时候总觉得自己没…

刷magisk模块后不能开机_刷Magisk模块开机卡Logo了怎么办?两种方法教你轻松解决...

虽然&#xff0c;Magisk由于工作原理的不同&#xff0c;其模块对系统的兼容性相比较于此前的Xposed框架模块要好得多&#xff0c;但是依旧有可能出现刷了模块之后&#xff0c;卡Logo&#xff0c;无法开机的情况。今天&#xff0c;小编就提供两种方式解决刷Magisk模块卡开机Logo…

Linux添加用户(user)到用户组(group)

转载自“http://xxx.11tea.com/blog/15654” 将一个用户添加到用户组中&#xff0c;千万不能直接用&#xff1a; usermod -G groupA 这样做会使你离开其他用户组&#xff0c;仅仅做为 这个用户组 groupA 的成员。 应该用 加上 -a 选项&#xff1a; usermod -a -G groupA user (…

Magicodes.IE 2.5.6.2发布

2.5.6.22021.10.13支持自定义列字体颜色&#xff0c;具体见PR#342&#xff0c;感谢xiangxiren修复日期格式化的问题&#xff0c;具体见PR#344&#xff0c;感谢ccccccmd2.5.6.12021.10.06修复 #337&#xff0c;bool?类型导出的映射问题2.5.6.02021.10.05合并Magicodes.EPPlus到…

html的标签和标记有啥区别,HTML 元素 b 和 strong 有什么区别?//(强调标签的理解)...

不要动不动就把英语的术语、名称或概念牵强地翻译成中文。不是「粗体和加重有什么区别」(原题如此)&#xff0c;是「HTML 标签 和 有什么区别」。HTML 的标签负责将内容标记为 HTML 元素&#xff0c;浏览器的默认 CSS 样式表负责按照 W3C 的建议来指定 HTML 元素的默认样式。…

一个让我很不爽的外包项目——奔驰Smart2015新官网

七月份的下半个月&#xff0c;有幸做了奔驰 Smart 2015年新官网&#xff0c;包括手机端和PC端的宣传页&#xff0c;地址&#xff1a; PC端手机端这里&#xff0c;为了证明这个是一个事实&#xff0c;我还特意的留存了两张截图&#xff1a; 这里只想说明这么几个问题&#xff1a…

备赛脱脂经验分享_IEO国际经济学奥林匹克初选宏观备赛经验分享

背景介绍&#xff1a;国际经济学奥林匹克(IEO)是13项国际科学类奥林匹克竞赛(International Science Olympiads)之一&#xff0c;面向全球高中学生&#xff0c;旨在鼓励对经济学、财务和商业感兴趣的学生&#xff0c;激发他们用创造性方式解决问题。IEO由诺贝尔经济学获奖者、哈…

为什么饮料瓶大都是圆的,牛奶盒却是方的?原因你想不到

全世界只有3.14 % 的人关注了爆炸吧知识每日看着电视玩着手机再喝着饮料那是相当美好但是喝了这么久的饮料你有没有想过一个问题为什么饮料瓶一般都是圆的&#xff1f;而牛奶盒却是方的&#xff1f;图片来源网络有的人可能会说饮料瓶要拿在手上当然是圆的舒服啊拿着一个方形的饮…

IIS相关问题及解决方案

1、问题&#xff1a;HTTP 错误 500.19 - Internal Server Error无法访问请求的页面,因为该页的相关配 可能原因&#xff1a;在自己使用IIS发布网站之后&#xff0c;自己所使用的当前账户的密码改变了。 解决方法&#xff1a;将用户才密码改回来即可.... 2. 转载于:https://www.…

博客园html源码编辑出错,博客园小技巧

作者&#xff1a;Vamei 出处&#xff1a;http://www.cnblogs.com/vamei 欢迎转载&#xff0c;也请保留这段声明。谢谢&#xff01;在博客园写博的半年中&#xff0c;我有时会纠结于一些诸如写作格式和显示效果之类的小问题。我想任何一个热衷于在这里写博客的人都可能会遇到类似…

使用零代码平台构建应用,应该怎样转变思路?

最近两年&#xff0c;越来越多的各类零代码产品在市场上出现&#xff0c;与此同时&#xff0c;企业的数字化转型的速度也越来越快&#xff0c;零代码产品已然成为了帮助企业数字化转型的利器。技术也在不断地演进&#xff0c;其核心目的就是让开发人员能够更专注于业务逻辑&…

看了这几幅图,感觉自己物理白学了!

全世界只有3.14 % 的人关注了爆炸吧知识看完觉得自己即将成为21世纪最伟大的科学家&#xff01;据说&#xff0c;物理老师看到这几幅图&#xff0c;会说不出话来……不信&#xff0c;转给你们老师看看&#xff0c;嘿嘿嘿……来源&#xff1a;物理知识大全

vue实现搜索框记录搜索历史_2018-09-13 基于Vue的搜索栏功能实现(we-ui)

视图代码搜索取消{{item.userName}}Script代码mounted() {this.$ajax({method: "get",url: "../static/json/user1.json" //}).then(response > {let _data1 response.data;if (response.data ! undefined) {this.userList _data1.userList;}}).catch…

异步编程模式学习

最近&#xff0c;在学习C#多线程编程&#xff0c;也看了园子里的很多大牛的关于多线程的文章&#xff0c;梳理下自己的思路&#xff0c;也总结下异步编程模式的学习。 很喜欢Jimmy Zhang的文章风格&#xff0c;在刚刚学习委托和事件的时候&#xff0c;Jimmy的文章的由浅入深的写…

坚持不懈,直到成功

坚持不懈&#xff0c;直到成功。 在古老的东方&#xff0c;挑选小公牛到技场格斗有一定的程序。它们被带进场&#xff0c;向手持长的斗士攻击&#xff0c;裁判以它受戳后再向斗牛士进攻的次数多来评定这只公牛的勇程度。从今往后&#xff0c;我须承认&#xff0c;我的生命每天都…

增长率不用计算机,事业单位行测:这类资料分析题根本不用计算

【导读】中公事业单位为帮助各位考生顺利通过事业单位招聘考试&#xff0c;今天为大家带来事业单位行政职业能力测试备考资料。很多同学认为资料分析列式容易&#xff0c;计算很难。但是&#xff0c;你知道吗?资料分析中有这几类题目是完全不需要动笔计算的&#xff0c;只要列…

在Web应用中使用localforage存储离线数据

在现代Web应用中&#xff0c;我们经常会需要在本地存储一些数据&#xff0c;一方面记住用户的一些状态&#xff0c;或个性化设置&#xff0c;尤其是可以缓存一些常用&#xff08;甚至全部&#xff09;的数据&#xff0c;实现更加强大和丰富的本地交互体验。传统上说&#xff0c…

CodeForces 486C Palindrome Transformation 贪心+抽象问题本质

题目&#xff1a;戳我 题意&#xff1a;给定长度为n的字符串&#xff0c;给定初始光标位置p&#xff0c;支持4种操作&#xff0c;left&#xff0c;right移动光标指向&#xff0c;up&#xff0c;down&#xff0c;改变当前光标指向的字符&#xff0c;输出最少的操作使得字符串为回…