<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          SignalR在React/Go技術(shù)棧的實踐

          共 5804字,需瀏覽 12分鐘

           ·

          2021-10-19 11:40


          哼哧哼哧半年,優(yōu)化改進(jìn)了一個運維開發(fā)web平臺。
          本文記錄SignalR在react/golang 技術(shù)棧的生產(chǎn)小實踐。

          01

          背景

          有個前后端分離的運維開發(fā)web平臺, 后端會間隔5分鐘同步一次數(shù)據(jù),現(xiàn)在需要將最新一次同步的時間推送到web前端。

          說到[web服務(wù)端推送],立馬想到SignalR,(我頭腦中一直有技術(shù)體系, 但一直沒實踐過。)

          SignalR是微軟推出的實時通信標(biāo)準(zhǔn)框架,內(nèi)部封裝了 websocket、服務(wù)端發(fā)送事件、長輪詢, 可以算是實時通信的大殺器,傳送門。

          實際編碼就是react寫SignalR客戶端,golang寫SignalR服務(wù)端,盲猜有對應(yīng)的輪子。

          02

          擼起袖子干


          果然, signalr的作者David Fowler實現(xiàn)了node、go版本, 這位老哥是.NET技術(shù)棧如雷貫耳的大牛:

          但是他的倉庫很久不更了,某德國大佬在此基礎(chǔ)上開了新github倉庫[1]繼續(xù)支持。

          SignalR的基本交互原理:

          (1) signalR提供了一組API, 用于創(chuàng)建從服務(wù)端到客戶端的遠(yuǎn)程過程調(diào)用(RPC),這個調(diào)用的具體體現(xiàn)是 :從服務(wù)端.NET 代碼調(diào)用位于客戶端的javascript 代碼

          (2) signalr提供了管理實例、連接、失連, 分組管控的API

          這里面最關(guān)鍵的一個概念是集線器Hub,其實也就是RPC領(lǐng)域常說的客戶端代理。
          服務(wù)端在baseUrl上建立signalr的監(jiān)聽地址;
          客戶端連接并注冊receive事件;

          服務(wù)端在適當(dāng)時候通過hubServer向HubClients發(fā)送數(shù)據(jù)。

          go服務(wù)端

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

          (2) 定義客戶端集線器hub,這里要實現(xiàn)HubInterface接口的幾個方法, 你還可以為集線器添加一些自定義方法。

          package?services

          import?(
          ?"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")
          }

          //?客戶端調(diào)用的函數(shù),?本例不用
          func?(h?*AppHub)?Send(message?string)?{
          ?h.Clients().All().Send("receive",?time.Now().Format("2006/01/02?15:04:05")?)
          }

          (3) 初始化集線器, 并在特定地址監(jiān)聽signalr請求。

          這個庫將signalr監(jiān)聽服務(wù)抽象為獨立的hubServer

          shub?:=?services.AppHub{}

          sHubSrv,err:=?signalr.NewServer(context.TODO(),
          ??signalr.UseHub(&shub),?//?這是單例hub
          ??signalr.KeepAliveInterval(2*time.Second),
          ??signalr.Logger(kitlog.NewLogfmtLogger(os.Stderr),?true))
          ?sHubSrv.MapHTTP(mux,?"/realtime")

          (4) 利用sHubServer在合適業(yè)務(wù)代碼位置向web客戶端推送數(shù)據(jù)。

          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客戶端需要監(jiān)聽的JavaScript事件名。

          react客戶端

          前端菜雞,跟著官方示例琢磨了好幾天。

          (1) 添加@microsoft/signalr 包

          (2) 在組件掛載事件componentDidMount初始化signalr連接

          實際也就是向服務(wù)端baseUrl建立HubConnection,注冊receive事件,等待服務(wù)端推送。

          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?below
          ????????connection.serverTimeoutInMilliseconds?=?60000;
          ?
          ????//?re-establish?the?connection?if?connection?dropped
          ????????connection.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?(
          ????????
          ??????????

          最新同步完成時間:?{this.state.message}??


          ????????

          ??????);
          ????}
          ??}

          export??default??Clock;

          (3) 將該react組件插入到web前端頁面


          03

          效果分析


          最后的效果如圖:

          效果分析:

          (1) web客戶端與服務(wù)器協(xié)商 傳輸方式http://localhost:9598/realtime/negotiate?negotiateVersion=1,
          返回可用的傳輸方式和連接標(biāo)識ConnectionId

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

          (2) web客戶端利用上面的ConnectionId向特定的服務(wù)器地址/realtime連接,建立傳輸通道,默認(rèn)優(yōu)先websocket。

          以上網(wǎng)絡(luò)交互,大部分會通過SignalR框架自動完成。

          源碼:Github Demo[2]

          引用鏈接

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

          實時通信技術(shù)大亂斗

          .NET WebSocket 核心原理初體驗

          .NET gRPC核心功能初體驗

          ●大前端快閃四:這次使用一個舒服的姿勢插入HttpClient攔截器

          ●大前端快閃三:多環(huán)境靈活配置react

          大前端快閃二:react開發(fā)模式 一鍵啟動多個服務(wù)

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

          “贊”“在看”

          體現(xiàn)態(tài)度很有必要!


          瀏覽 90
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产一级a毛一级a看免费观看 | 天天无码高清 | 日韩伦理精品在线 | 黄色成人视频网站在线观看 | 影音先锋噜噜资源 |