我们公司现在需要在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",为此我查阅了大量资料才解决了这个问题