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

01

背景

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

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

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

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

02

撸起袖子干

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

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

SignalR的基本交互原理:

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

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

这里面最关键的一个概念是集线器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

效果分析

最后的效果如图:

效果分析:

(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。

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

源码:Github Demo[2]

引用链接

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

●实时通信技术大乱斗

●.NET WebSocket 核心原理初体验

●.NET gRPC核心功能初体验

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

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

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

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

“赞”“在看”

体现态度很有必要!

SignalR在React/Go技术栈的实践相关推荐

  1. React+Redux技术栈核心要点解析(上篇)

    感谢作者郭永峰的授权发布. 作者:郭永峰,前端架构师,现用友网络 FED团队负责人,目前主要负责企业级应用前端技术平台建设工作,在前端工程化实现.Node 应用开发.React技术.移动开发等方向有丰 ...

  2. React+Redux技术栈核心要点解析(中篇)

    感谢作者郭永峰的授权发布. 作者:郭永峰,前端架构师,现用友网络 FED团队负责人,目前主要负责企业级应用前端技术平台建设工作,在前端工程化实现.Node 应用开发.React技术.移动开发等方向有丰 ...

  3. React+Redux技术栈核心要点解析(下篇)

    感谢作者郭永峰的授权发布. 作者:郭永峰,前端架构师,现用友网络 FED团队负责人,目前主要负责企业级应用前端技术平台建设工作,在前端工程化实现.Node 应用开发.React技术.移动开发等方向有丰 ...

  4. React技术栈——webpack

    一直在用fis3,也能完美满足目前业务需求.我厂的scrat也有大量的feature贴合业务线. 最近在看React,要打通React的技术栈,学习Webpack是必不可少的了. 从npm上安装很简单 ...

  5. react 技术栈项目轻量化方案调研

    react 技术栈项目轻量化方案调研 团队的新项目,无论是pc端的还是移动端的,都已全面转移到了 react 的技术栈. 然而,对移动端来说,react 框架脚本的体量还是有些偏大. 在后续项目比较成 ...

  6. 深入react技术栈(3):React组件

    我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣 终于说出最为关心的react组件了.在react形成之前,组件封装都是在摸索之中 组件的演变 class定义组件的样式 这样可以方便的 ...

  7. 深入react技术栈(2):JSX语法

    JSX的由来 DOM元素 组件元素 JSX基本语法 XML基本语法 元素类型 .我们讲到两种不同的元素:DOM元素和组件元素 在JSX里面有对应 注释 元素属性 Boolean属性  展开属性 自定义 ...

  8. 深入react技术栈(1):React简介

    我是歌谣 放弃很容易 但是坚持一定很酷 微信公众号关注前端小歌谣获取前端知识 前言 专注视图层 Virtual DOM 真实页面对应一个DOM树.在传统页面的开发模式中 每次更新页面都需要手动更新 D ...

  9. axure9数据统计插件_WMDA:大数据技术栈的综合实践

    一.概述 WMDA是58自主开发的用户行为分析产品,同时也是一款支持无埋点的数据采集产品,只需要在第一次使用的时候加载一段SDK代码,即可采集全量.实时的PC.M.APP三端以及小程序的用户行为数据. ...

最新文章

  1. mysql中的各种锁把我搞糊涂啦~
  2. 如何加强网络安全 这7种建议你不可不知!
  3. 南航计算机硬件实验,南航80X86微机原理及接口技术实验指导书.pdf
  4. 华为p40鸿蒙系统价格有好高,鸿蒙系统版本华为P50新机的曝光,华为P40处境悲惨价格骤降...
  5. python网络编程---TCP服务器
  6. Ignite 配置更新Oracle JDBC Drive
  7. ppt转pdf软件免费版
  8. java的继承和访问_Java基础篇:如何解决成员的访问和继承?
  9. 学习Kubernetes 和容器技术体系的最佳方法
  10. html不同类别的列表设置,HTML --列表
  11. Kontakt 6 for Mac安装 - 专业的音乐采样器,行业标准式的采样器
  12. Lesson 06 for Plotting in R for Biologists
  13. Android 开机自启动应用
  14. 【mac】配置本地数据库
  15. app消息推送接入流程
  16. chrome插件charset与fireshot
  17. java根据身份证号码计算年龄的方法(精确到日)
  18. 华硕美版路由器RT-AC1200G+解决无线信号弱问题
  19. 机器人轨迹规划(熊友伦)
  20. C语言教程(七):函数

热门文章

  1. 将 iOS 应用的体积控制在 20MB 以内对于其下载量有很明显的影响吗?
  2. linux的内核有多小,Linux 内核有小bug?
  3. idea tomcat启动成功但是访问方面都是404_IDEA相关配置【集成Tomcatamp;项目部署】...
  4. mysql8用户管理
  5. 父元素 高度固定,如何使其中的文字垂直居中?
  6. iptables (2) 基本配置
  7. 面向对象——一起来复习托付与事件!
  8. Koa -- 基于 Node.js 平台的下一代 web 开发框架
  9. eshop截取字符串长度 和去掉省略号
  10. IDA64 Fatal error before kernel init