浏览器中 SignalR 连接示例及注意事项
官方文档地址:
ASP.NET Core SignalR configuration | Microsoft Learn
注意事项:
1. 浏览器中websocket 不支持自定义请求头, 如果需要自定义请求头, 只能使用 http 方式, 对应配置项: withUrl 第二个参数中增加 transport: SignalR.HttpTransportType.LongPolling 配置
.withUrl(`/ProductClientMsgHub}`, {transport: SignalR.HttpTransportType.LongPolling, // 使用 LongPolling headers: defaultHeaders,})
2. token 携带可以使用官方推荐的 accessTokenFactory
.withUrl(`/ProductClientMsgHub}`, {skipNegotiation: true,transport: SignalR.HttpTransportType.WebSockets, accessTokenFactory: () => util.cookies.get('token'), // 自动附加 Authorization Bearer})
3. withUrl 可以使用的配置项
示例代码:
import * as SignalR from "@microsoft/signalr";
import { Notification } from "element-ui";
import util from "@/libs/util.js";
import store from "@/store/index";let connection = null;
const baseUrl = '192.168.x.x:xxxx'// 创建连接
const createConnection = (headers = {}) => {// 设置连接头信息const defaultHeaders = {'LineId': headers.LineId || '','OperationId': headers.OperationId || '','ClientType': headers.ClientType || 'PC','OrganizeId': headers.OrganizeId || Number(localStorage.getItem('organizeId')),'Authorization': `Bearer ${util.cookies.get('token')}`}console.log('创建连接,headers:', defaultHeaders)connection = new SignalR.HubConnectionBuilder().configureLogging(SignalR.LogLevel.Information).withUrl(`${baseUrl}/ProductClientMsgHub?LineId=${headers.LineId}&OperationId=${headers.OperationId}&ClientType=${headers.ClientType}&OrganizeId=${headers.OrganizeId}`, {skipNegotiation: true, // 跳过协商transport: SignalR.HttpTransportType.WebSockets, // transport: SignalR.HttpTransportType.LongPolling,withCredentials: true,// headers: defaultHeaders,accessTokenFactory: () => util.cookies.get('token'), // 自动附加 Authorization Bearer}).withAutomaticReconnect({nextRetryDelayInMilliseconds: () => {return 5000; // 每5秒重连一次},}).build();connection.keepAliveIntervalInMilliseconds = 15 * 1000; // 心跳检测15sconnection.serverTimeoutInMilliseconds = 30 * 60 * 1000; // 超时时间30m// 断开连接connection.onclose(async (error) => {console.log('SignalR 连接断开')if (error) {console.error('断开原因:', error)}})// 重连中connection.onreconnecting((error) => {console.log('SignalR 正在重连...')if (error) {console.error('重连原因:', error)}Notification({title: "提示",message: "服务器已断线,正在重连...",type: "warning",position: "bottom-right",})})// 重连成功connection.onreconnected((connectionId) => {console.log('SignalR 重连成功!')console.log('新的连接ID:', connectionId)Notification({title: "提示",message: "服务器重连成功",type: "success",position: "bottom-right",})})return connection;
}// 启动连接
const startConnection = async (headers = {}) => {try {// 如果连接不存在或已断开,创建新连接if (!connection || connection.state === SignalR.HubConnectionState.Disconnected) {console.log('正在连接 SignalR 服务...', headers)connection = createConnection(headers)await connection.start()console.log('SignalR 连接成功!')console.log('连接状态:', connection.state)console.log('连接ID:', connection.connectionId)return connection} else {console.log('当前连接状态:', connection.state)return connection}} catch (err) {console.error('SignalR 连接失败:', err)console.error('错误详情:', {message: err.message,stack: err.stack})}
}// 获取连接实例
const getConnection = () => {if (!connection) {console.warn('SignalR 连接未创建,请先调用 startConnection')return null}return connection
}export { getConnection as signalR, startConnection };