如何在SignalR的accessTokenFactory中异步传递更新后的访问令牌
问题根因
你的代码存在两个核心错误导致异步逻辑不生效:
accessTokenFactory函数没有返回值,SignalR拿到undefined后会直接发起请求,不会等待异步逻辑执行.done()回调内的return语句仅作用于回调函数本身,无法将令牌返回给accessTokenFactory的调用方
修复方案
jQuery 3.0+ 版本的$.get方法返回的jqXHR对象原生兼容Promise规范,你只需要在accessTokenFactory里直接返回这个Ajax请求对象即可,SignalR会自动等待请求完成,拿到令牌后再发起服务端调用:
var connection = new signalR.HubConnectionBuilder() .withUrl(baseUrl + 'hub/report?groupName=' + groupName, { skipNegotiation: true, transport: signalR.HttpTransportType.WebSockets, accessTokenFactory: () => { // 直接返回Ajax请求对象即可,SignalR支持接收Promise类型的返回值 return $.get('api/user/getAccessToken/'); } }) .withAutomaticReconnect() .configureLogging(signalR.LogLevel.Debug) .build();
可选优化
如果你需要对令牌做缓存、格式处理或者错误捕获,可以用async/await的写法实现更灵活的逻辑:
accessTokenFactory: async () => { // 优先读取缓存的未过期令牌,减少不必要的接口请求 const cachedToken = sessionStorage.getItem('signalr_access_token'); const expireTime = sessionStorage.getItem('signalr_token_expire'); if (cachedToken && Date.now() < Number(expireTime)) { return cachedToken; } try { // 等待异步请求返回新令牌 const newToken = await $.get('api/user/getAccessToken/'); // 缓存令牌,这里假设令牌有效期为5分钟,可根据实际业务调整 sessionStorage.setItem('signalr_access_token', newToken); sessionStorage.setItem('signalr_token_expire', String(Date.now() + 5 * 60 * 1000)); // 如果后端要求Authorization头带Bearer前缀,此处返回 `Bearer ${newToken}` 即可 return newToken; } catch (e) { console.error('获取SignalR鉴权令牌失败', e); throw e; } }
注意事项
如果你的服务端鉴权逻辑要求令牌放在Authorization请求头而非查询参数中,需要去掉skipNegotiation: true配置,WebSocket传输模式下默认会把令牌放在查询参数中传递。
内容的提问来源于stack exchange,提问作者Utsav Dawn
相关产品推荐
相关产品推荐

