自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

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

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

[[429700]]

本文轉(zhuǎn)載自微信公眾號「精益碼農(nóng)」,作者有態(tài)度的馬甲 。轉(zhuǎn)載本文請聯(lián)系精益碼農(nóng)公眾號。

一.背景

有個前后端分離的運維開發(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)的輪子。

二.擼起袖子干

果然, 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接口的幾個方法, 你還可以為集線器添加一些自定義方法。

  1. package services 
  2.  
  3. import ( 
  4.  "github.com/philippseith/signalr" 
  5.  log "github.com/sirupsen/logrus" 
  6.  "time" 
  7.  
  8. type AppHub struct{ 
  9.   signalr.Hub 
  10.  
  11. func (h *AppHub) OnConnected(connectionID string) { 
  12.  // fmt.Printf("%s connected\n", connectionID) 
  13.  log.Infoln(connectionID," connected\n" ) 
  14.  
  15. func (h *AppHub) OnDisconnected(connectionID string) { 
  16.  log.Infoln(connectionID," disconnected\n"
  17.  
  18. // 客戶端調(diào)用的函數(shù), 本例不用 
  19. func (h *AppHub) Send(message string) { 
  20.  h.Clients().All().Send("receive"time.Now().Format("2006/01/02 15:04:05") ) 

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

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

  1. shub := services.AppHub{} 
  2.  
  3. sHubSrv,err:= signalr.NewServer(context.TODO(), 
  4.   signalr.UseHub(&shub), // 這是單例hub 
  5.   signalr.KeepAliveInterval(2*time.Second), 
  6.   signalr.Logger(kitlog.NewLogfmtLogger(os.Stderr), true)) 
  7.  sHubSrv.MapHTTP(mux, "/realtime"

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

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

注意:上面的receive方法是后面react客戶端需要監(jiān)聽的JavaScript事件名。

react客戶端

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

(1) 添加@microsoft/signalr 包

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

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

  1. import React from 'react'
  2. import { 
  3.   JsonHubProtocol, 
  4.   HubConnectionState, 
  5.   HubConnectionBuilder, 
  6.   HttpTransportType, 
  7.   LogLevel, 
  8. from '@microsoft/signalr'
  9.  
  10. class Clock extends React.Component { 
  11.     constructor(props) { 
  12.       super(props); 
  13.       this.state = { 
  14.         message:''
  15.         hubConnection: null
  16.       }; 
  17.     } 
  18.    
  19.     componentDidMount() { 
  20.       const connection = new HubConnectionBuilder() 
  21.         .withUrl(process.env.REACT_APP_APIBASEURL+"realtime", { 
  22.         }) 
  23.         .withAutomaticReconnect() 
  24.         .withHubProtocol(new JsonHubProtocol()) 
  25.         .configureLogging(LogLevel.Information) 
  26.         .build(); 
  27.   
  28.     // Note: to keep the connection open the serverTimeout should be 
  29.     // larger than the KeepAlive value that is set on the server 
  30.     // keepAliveIntervalInMilliseconds default is 15000 and we are using default 
  31.     // serverTimeoutInMilliseconds default is 30000 and we are using 60000 set below 
  32.         connection.serverTimeoutInMilliseconds = 60000; 
  33.   
  34.     // re-establish the connection if connection dropped 
  35.         connection.onclose(error => { 
  36.             console.assert(connection.state === HubConnectionState.Disconnected); 
  37.             console.log('Connection closed due to error. Try refreshing this page to restart the connection', error); 
  38.         }); 
  39.      
  40.         connection.onreconnecting(error => { 
  41.             console.assert(connection.state === HubConnectionState.Reconnecting); 
  42.             console.log('Connection lost due to error. Reconnecting.', error); 
  43.         }); 
  44.      
  45.         connection.onreconnected(connectionId => { 
  46.             console.assert(connection.state === HubConnectionState.Connected); 
  47.             console.log('Connection reestablished. Connected with connectionId', connectionId); 
  48.         }); 
  49.          
  50.         this.setState({ hubConnection: connection}) 
  51.  
  52.         this.startSignalRConnection(connection).then(()=> { 
  53.               if(connection.state === HubConnectionState.Connected) { 
  54.                 connection.invoke('RequestSyncTime').then(val => { 
  55.                   console.log("Signalr get data first time:",val); 
  56.                   this.setState({ message:val }) 
  57.                 }) 
  58.               } 
  59.         }) ; 
  60.  
  61.         connection.on('receive', res => { 
  62.           console.log("SignalR get hot res:", res) 
  63.             this.setState({ 
  64.               message:res 
  65.             }); 
  66.         }); 
  67.     } 
  68.    
  69.     startSignalRConnection = async connection => { 
  70.       try { 
  71.           await connection.start(); 
  72.           console.assert(connection.state === HubConnectionState.Connected); 
  73.           console.log('SignalR connection established'); 
  74.       } catch (err) { 
  75.           console.assert(connection.state === HubConnectionState.Disconnected); 
  76.           console.error('SignalR Connection Error: ', err); 
  77.           setTimeout(() => this.startSignalRConnection(connection), 5000); 
  78.       } 
  79.     }; 
  80.    
  81.     render() { 
  82.       return ( 
  83.         <div style={{width: '300px',float:'left',marginLeft:'10px'}} > 
  84.           <h4>最新同步完成時間: {this.state.message}  </h4> 
  85.         </div> 
  86.       ); 
  87.     } 
  88.   } 
  89.  
  90. export  default  Clock; 

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

三.效果分析

最后的效果如圖:

效果分析:

(1) web客戶端與服務(wù)器協(xié)商 傳輸方式http://localhost:9598/realtime/negotiate?negotiateVersion=1,

返回可用的傳輸方式和連接標(biāo)識ConnectionId。

  1.     "connectionId""hkSNQT-pGpZ9E6tuMY9rRw=="
  2.     "availableTransports": [{ 
  3.         "transport""WebSockets"
  4.         "transferFormats": ["Text""Binary"
  5.     }, { 
  6.         "transport""ServerSentEvents"
  7.         "transferFormats": ["Text"
  8.     }] 

(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

 

責(zé)任編輯:武曉燕 來源: 精益碼農(nóng)
相關(guān)推薦

2017-11-22 13:01:03

Go技術(shù)棧構(gòu)建

2019-09-23 19:30:27

reduxreact.js前端

2023-10-26 07:37:18

ReactVue項目

2023-07-21 01:12:30

Reactfalse?變量

2021-10-18 09:08:27

Go分段棧連續(xù)棧

2020-09-17 06:42:31

ReactStoreon前端

2023-06-07 08:32:32

引擎技術(shù)while

2017-02-28 21:57:05

React組件

2019-07-20 23:30:48

開發(fā)技能代碼

2019-07-22 10:42:11

React組件前端

2023-02-28 12:12:21

語音識別技術(shù)解碼器

2023-12-05 15:58:06

React開發(fā)

2017-09-07 15:53:51

Go支付Java

2020-01-07 15:40:43

React前端技術(shù)準(zhǔn)則

2022-08-19 09:01:59

ReactTS類型

2020-06-01 09:40:06

開發(fā)ReactTypeScript

2020-06-03 16:50:24

TypeScriptReact前端

2020-09-28 10:05:57

數(shù)據(jù)工具技術(shù)

2018-06-06 10:50:18

容器開源

2022-04-06 15:58:25

火山引擎差分隱私LDPDC
點贊
收藏

51CTO技術(shù)棧公眾號