vue3+TS使用@microsoft/signalr实现及时聊天功能。实现及时聊天的token无感刷新,断线自动重连

我们公司现在需要在app上内置一个聊天功能能让app上的用户直接联系到我们客服人员。后端使用的是.net所以后端采用signalr来做及时聊天。直接上代码。

环境:vite+vue+ts

一、需要下载的插件包:@microsoft/signalr

二、拿到后端给我的触发通讯的方法名

这个去找自己的后端拿到以及这些方法需要传递什么参数等

三、封装一个方法去做链接

我这里采用的ES6的class的方式去做因为,我们这边的signalR接口是有token时效的所以采用class的方式去做

//建立signalR链接,然后存放在pinia中
class getChats extends signalR.DefaultHttpClient {
  constructor() {
    // constructor在这里没有用到所以就随便给super了个值防止报错
    super(console);
  }
  public async send(
    request: signalR.HttpRequest
  ): Promise<signalR.HttpResponse> {
    const authHeader = handleStorage(); //获取token的方法
    request.headers = { ...authHeader }; // 给signalR链接添加请求头
    try {
      const response = await super.send(request);
      return response;
    } catch (error) {
      if (error instanceof signalR.HttpError) {
        const err = error as signalR.HttpError;
        if (err.statusCode == 401) {
          // 如果返回的是401就表示token过期那么就需要去做token的刷新
          const authHeader = await getStorage();
          request.headers = { ...authHeader };
        }
      } else {
        throw error;
      }
    }
    return super.send(request);
  }
}

四、去搭建链接

// 保存的后端及时通讯接口地址
const D = {
  dev: "http://101.43.158.22:5001",
  dev2: "http://192.168.1.30:5001",
  pro: import.meta.env.VITE_API_URL,
};
// 最后只需要去导出这方法然后传入你的signalR链接
export const getChat = new signalR.HubConnectionBuilder()
  .withUrl(`${D.dev}/hubs/chathub`, {
    httpClient: new getChats(),
  })
  .configureLogging(signalR.LogLevel.Information)
  .build() as signalR.HubConnection;

完整的signalR链接代码,其中做了signalR的token无感刷新

import * as signalR from "@microsoft/signalr"; //及时聊天插件
import { getStorage, handleStorage } from "@/stores/modules/getToken"; //token过期后刷新token的方式
//建立signalR链接,然后存放在pinia中
class getChats extends signalR.DefaultHttpClient {
  constructor() {
    // constructor在这里没有用到所以就随便给super了个值防止报错
    super(console);
  }
  public async send(
    request: signalR.HttpRequest
  ): Promise<signalR.HttpResponse> {
    const authHeader = handleStorage(); //获取token的方法
    request.headers = { ...authHeader }; // 给signalR链接添加请求头
    try {
      const response = await super.send(request);
      return response;
    } catch (error) {
      if (error instanceof signalR.HttpError) {
        const err = error as signalR.HttpError;
        if (err.statusCode == 401) {
          // 如果返回的是401就表示token过期那么就需要去做token的刷新
          const authHeader = await getStorage();
          request.headers = { ...authHeader };
        }
      } else {
        throw error;
      }
    }
    return super.send(request);
  }
}
// 保存的后端及时通讯接口地址
const D = {
  dev: "http://101.43.158.22:5001",
  dev2: "http://192.168.1.30:5001",
  pro: import.meta.env.VITE_API_URL,
};
// 最后只需要去导出这方法然后传入你的signalR链接
export const getChat = new signalR.HubConnectionBuilder()
  .withUrl(`${D.dev}/hubs/chathub`, {
    httpClient: new getChats(),
  })
  .configureLogging(signalR.LogLevel.Information)
  .build() as signalR.HubConnection;

getStorage, handleStorage两个刷新token的方法

import md5 from "blueimp-md5";
import { refreshToken } from "@/api/login"; //刷新token接口
export const getStorage = async () => {
  const token = localStorage.getItem("token");
  if (!token) return;
  const T = JSON.parse(token);
  // 刷新token接口
  const data = await refreshToken({
    accessToken: T.refreshToken,
  });
  if (data.statusCode == 200) {
    // 重新设置token
    localStorage.setItem("token", JSON.stringify(data.data));
    let accessToken = data.data.accessToken;
    let user_id = data.data.adminUserId;
    let timeStamp = new Date().getTime().toFixed();
    return {
      Authorization: "Bearer " + accessToken,
      timeStamp: timeStamp,
      SignToken: md5(user_id + ":" + timeStamp),
    };
  }
};

// 直接获取本地保存的token以及刷新token
export const handleStorage = () => {
  // debugger;
  const token = localStorage.getItem("token");
  if (!token) return;
  const T = JSON.parse(token);
  let accessToken = T.accessToken;
  let user_id = T.adminUserId;
  let timeStamp = new Date().getTime().toFixed();

  return {
    Authorization: "Bearer " + accessToken,
    timeStamp: timeStamp,
    SignToken: md5(user_id + ":" + timeStamp),
  };
};

五、然后就是去调用我们会封装好的链接去做链接就行了

六、最后将保存在pinia里面的方法调用后端给的发送消息方法就可以完成及时通讯啦

        1、监听接收消息的方法直接写在vue文件中的setup下即可,v2的可以写在mounted中

此方法接收两个参数,我这边是第一个发送消息者的聊天id,第二个是消息体。具体的根据你们后端这边返回的为主

        2、监听发送方法

效果图

总结:想要做到连接的及时刷新使用网上的很多方法直接链接是不行的,如果有需要使用到token刷新就需要用到全新的class类写法。

因为这个是我们app这边的客户需要跟客服进行通讯所以下一次还会出一个uniapp+signalR的及时通讯。市面上很多用于uniapp的signalR方法都是在开发环境下使用的一旦跑到真机环境就会报错:"ReferenceError: require is not defined",为此我查阅了大量资料才解决了这个问题

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值