本文对应的环境:React + ANTD + .NET CORE WEB API + SignalR
效果图:
前端代码
用到的包和版本如下:
前端组件代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
| import React from 'react'; import { notification, Typography } from 'antd'; import { ExclamationCircleFilled } from '@ant-design/icons'; import * as signalR from '@microsoft/signalr'; import styles from './style.less'; import config from '../../config'; import urlParam from '../../utils/UrlParamHelper'; const { Paragraph, Link } = Typography; class Notification extends React.Component { constructor (props) { super(props); } render () { return null; } componentDidMount () { const protocol = new signalR.JsonHubProtocol(); const transport = signalR.HttpTransportType.WebSockets; const options = { transport; } this.connection = new signalR.HubConnectionBuilder() .withUrl(`${config.baseURL}api/TaskNotification?token=${urlParam.token}`, options) .withHubProtocol(protocol) .withAutomaticReconnect() .build(); this.connection.on('TaskNotifiy', this.onNotifReceived); this.connection.start() .then(() => console.info('SignalR Connected')) .catch(err => console.error('SignalR Connection Error: ', err)); } componentWillUnmount () { this.connection.stop(); } onNotifReceived (taskNo, taskTitle) { notification.info({ message: '任务提醒:', description: {taskTitle}, placement: 'bottomRight', duration: null, icon: <ExclamationCircleFilled className={styles.icon} /> }) } }; export default Notification;
|
后端代码:
.NET CORE 版本为 2.2
后端项目结构:
TaskNotificationHub.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public class TaskNotificationHub : Hub { private static IServiceProvider _serviceProvider;
public static void Init(IServiceProvider serviceProvider) { _serviceProvider = serviceProvider; }
public async override Task OnConnectedAsync() { var token = Context.GetHttpContext().Request.Query["token"].ToString();
if (!string.IsNullOrEmpty(token)) { { await RedisClient.Instance.SetAsync("缓存key-用户标识", this.Context.ConnectionId); } } await base.OnConnectedAsync(); }
public async override Task OnDisconnectedAsync(Exception exception) { var token = Context.GetHttpContext().Request.Query["token"].ToString(); if (!string.IsNullOrEmpty(token)) { await RedisClient.Instance.RemoveAsync("缓存key-用户标识"); } } await base.OnDisconnectedAsync(exception); } }
|
Startup.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public void ConfigureServices(IServiceCollection services) {
services.AddCors( options => options.AddPolicy( DefaultCorsPolicyName, builder => builder.WithOrigins("http://localhost:3000") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() ) );
services.AddSignalR(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); }
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactor) { app.UseCors(DefaultCorsPolicyName);
var webSocketOptions = new WebSocketOptions() { KeepAliveInterval = TimeSpan.FromSeconds(120), ReceiveBufferSize = 4 * 1024 }; webSocketOptions.AllowedOrigins.Add("http://localhost:3000"); app.UseWebSockets(webSocketOptions); app.UseSignalR(routes => { routes.MapHub<TaskNotificationHub>("/api/TaskNotification"); });
app.UseMvc(); }
|
Controller
这里直接通过 Controller 来说明如何发送消息到客户端
TaskController.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| private readonly IHubContext<TaskNotificationHub> _hubContext;
public TaskController( IHubContext<TaskNotificationHub> hubContext) { _hubContext = hubContext; }
[HttpPost] public async Task<ResultInfo> NotifyAsync(string args) { var connectionId = await RedisClient.Instance.GetAsync<string>("缓存key"); await _hubContext.Clients.Client(connectionId).SendAsync("TaskNotifiy", content1, content2,...contentN);
return ResultInfo.Success(); }
|
nginx
如果你使用了 nginx,则需要进行下如下配置:
1 2 3 4 5 6 7 8 9 10 11
| location {你的路径} { proxy_connect_timeout 120; proxy_read_timeout 120; proxy_send_timeout 120; proxy_pass {你的站点}; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }
|