vue+.net 利用signalR实现实时推送和显示通知消息

后端(.net)

创建SignalR Hub

创建类SysNoticeHub.cs

 public class SysNoticeHub : Hub
 {
 }
模拟接口发送在线通知
[Route("api/sysnotice")]
[ApiController]
public class SysNoticeController : BaseController
{
    private readonly IHubContext<SysNoticeHub> _hubContext;

    public SysNoticeController(IHubContext<SysNoticeHub> hubContext)
    {
        _hubContext = hubContext;
    }

    /// <summary>
    /// 发送在线消息
    /// </summary>
    /// <param name="id">消息id</param>
    /// <returns></returns>
    [HttpPost("onnline/{id}")]
    public async Task<IActionResult> SendOnlineAsync([FromRoute] int id)
    {
        await _hubContext.Clients.All.SendAsync("ReceiveSysNotice", id, "测试标题", "测试内容");
        return SUCCESS("发送成功");
    }

}
配置跨域

如果前后端不在一个域名下,需要启用CORS

builder.Services.AddCors(options =>
{
    options.AddPolicy("cors", builder =>
    {
        builder.SetIsOriginAllowed(_ => true)
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials();
    });
});

app.UseCors("cors");
配置signalR服务

Program.cs

builder.Services.AddSignalR();

app.MapHub<SysNoticeHub>("/hub/notice");

前端(vue2)

安装signalR客户端库
npm install @microsoft/signalr@6.0.6
配置环境变量

打开.env.development文件(生产环境变量的值根据实际情况自定义)

VUE_APP_BASE_WS = "/dev-ws"
VUE_APP_BASE_URL_WS = "http://localhost:5068/hub"
创建signalR服务

在utils文件夹下创建signalR.js

import * as signalR from "@microsoft/signalr";
import { getToken } from "@/utils/cookie";

export default {
  SR: null,

  start(url, callFunc) {
    const connection = new signalR.HubConnectionBuilder() 
      .withUrl(`${process.env.VUE_APP_BASE_WS}/` + url, {
        headers: {
          Authorization: `Bearer ${getToken()}`,
        },
        accessTokenFactory: () => {
          return `${getToken()}`;
        },
      })
      .withAutomaticReconnect(new ReconnectPolicy()) //开启自动重连机制
      .configureLogging(signalR.LogLevel.Error) //配置日志级别为Error
      .build();

    //保存连接对象到SR属性
    this.SR = connection;

    //监听连接关闭事件
    connection.onclose((error) => {
      console.log("hub连接断开:" + error);
    });
    //监听重连事件
    connection.onreconnecting((error) => {
      console.log("正在尝试重新连接...", error);
    });
    //监听重连成功事件
    connection.onreconnected((connectionId) => {
      console.log("hub重新连接成功,新的连接id:" + connectionId);
    });

    //调用传入的回调函数,并将连接对象作为参数传递
    if (typeof callFunc === "function") {
      callFunc(connection);
    }

    connection
      .start()
      .then(() => {
        console.log("SignalR 连接成功");
      })
      .catch((error) => {
        console.log("启动 SignalR 连接时出错:", error);
      });
  },
};

class ReconnectPolicy {
  nextRetryDelayInMilliseconds(retryContext) {
    // 每次重连间隔都设置为 3000 毫秒
    return 3000;
  }
}

创建公告通知服务

创建hubs文件夹,在该目录下创建noticeHub.js,配置内容如下

import signalR  from "@/utils/signalR"
import { Notification } from 'element-ui';
const receiveMsg = (connection)=>{
    connection.on("ReceiveSysNotice",(id,title,content)=>{
        Notification({
            title:title,
            message:content,
            duration:3000  //3秒后自动关闭
        })
    })
}

export default(()=>{
    signalR.start('notice',receiveMsg);
})
挂载signalR通知连接

打开main.js文件,配置如下内容

import noticeSignalR from '@/hubs/noticeHub'

new Vue({
  render: h => h(App),
  mounted() {
     noticeSignalR();
  }
}).$mount('#app')
配置请求代理

打开vue.config.js,配置如下内容

这里目前存在两个问题,暂时没想出原因,若有前端大神,望留言指教。

问题一:

pathRewrite: {["^dev-ws"]: ""}rewrite: (path) => path.replace(/^/dev-ws/, '') 二者的作用应该是一样的,都是将请求路径中带有dev-ws内容替换为空,但用rewrite之后请求会返回404,用pathRewrite没问题(不考虑bypass函数内部出问题,因为没有这个函数也会这样)。

问题二:

往请求标头(Request Headers)和 响应标头(Response Headers)分别添加自定义参数x-real-proxy-url,但实际效果是响应标头能正常显示x-real-proxy-url变量,请求标头未显示x-real-proxy-url变量,不知道是浏览器安全策略导致的还是需要服务端配置其它信息。

 devServer: {
    proxy: {
      [`${process.env.VUE_APP_BASE_WS}`]: {
        target: `${process.env.VUE_APP_BASE_URL_WS}`,
        changeOrigin: true,
        pathRewrite: {
          ["^" + process.env.VUE_APP_BASE_WS]: "",
        },
        //rewrite: (path) => path.replace(/^\/dev-ws/, ''),
        ws: true, //开启 WebSocket 代理
        bypass(req, res, options) {
          const proxyUrl = options.target;
          //const rewriteUrl = options.rewrite(req.url);
          const rewriteUrl = req.url;
          const realUrl = proxyUrl + rewriteUrl;
          console.log("Real Proxy URL:", realUrl); 
          req.headers["x-real-proxy-url"] = realUrl;
          res.setHeader("x-real-proxy-url", realUrl);
          return undefined;
        },
      },
    }
}

效果

服务端调用接口发送通知

客户端实时收到并显示通知

posted @   相遇就是有缘  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 2分钟学会 DeepSeek API,竟然比官方更好用!
· .NET 使用 DeepSeek R1 开发智能 AI 客户端
· 10亿数据,如何做迁移?
· 推荐几款开源且免费的 .NET MAUI 组件库
· c# 半导体/led行业 晶圆片WaferMap实现 map图实现入门篇
  1. 1 我记得 赵雷
  2. 2 北京东路的日子 汪源
  3. 3 把回忆拼好给你 王贰浪
把回忆拼好给你 - 王贰浪
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

Not available

点击右上角即可分享
微信分享提示