如何通过ASP.NET Core BFF实现Angular应用与SignalR服务端的连接?
问题分析与解决方案
核心问题:SignalR客户端会保留初始请求的基地址(BFF地址),即使协商请求被重定向到SignalR Hub,后续的连接请求依然会指向BFF,而非直接访问SignalR服务端。这是因为SignalR的协商响应中返回的连接URL虽基于重定向后的地址生成,但客户端会忽略该URL,继续使用最初配置的Hub端点。
问题根源
- SignalR客户端的设计逻辑:初始化时绑定指定的Hub URL,重定向不会触发客户端更新连接目标地址。
- 代码异步错误:
GetTokenAsync是异步方法,但未使用await,导致accessToken实际是Task<string>类型,Authorization头格式完全错误。
正确实现方式
不要用重定向,采用BFF代理转发的方案,符合BFF模式的设计原则,同时解决地址绑定问题:
修改BFF端点代码
public static async Task<IResult> GetChatHubInfo(HttpContext context, string negotiateVersion, CancellationToken cancellationToken) { // 正确异步获取访问令牌 var accessToken = await context.GetTokenAsync("access_token"); if (string.IsNullOrEmpty(accessToken)) { return Results.Unauthorized(); } // 初始化HttpClient用于转发请求到SignalR Hub using var httpClient = new HttpClient(); httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken); // 构造SignalR Hub的协商请求地址 var requestUri = $"https://localhost:7271/negotiate?negotiateVersion={negotiateVersion}"; var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri); // 复制原始请求的内容与头信息(SignalR协商为POST请求,带JSON内容) using var requestContent = new StreamContent(context.Request.Body); foreach (var header in context.Request.ContentType) { requestContent.Headers.TryAddWithoutValidation(header.Key, header.Value); } requestMessage.Content = requestContent; // 发送请求并获取SignalR Hub的协商响应 var response = await httpClient.SendAsync(requestMessage, cancellationToken); // 将协商响应原封不动返回给Angular客户端 var responseContent = await response.Content.ReadAsStringAsync(cancellationToken); var responseHeaders = new Dictionary<string, string>(); // 复制响应头 foreach (var header in response.Headers) { responseHeaders[header.Key] = string.Join(", ", header.Value); } foreach (var header in response.Content.Headers) { responseHeaders[header.Key] = string.Join(", ", header.Value); } return Results.Text( responseContent, response.Content.Headers.ContentType?.ToString(), response.StatusCode, responseHeaders ); }
Angular客户端配置
确保SignalR客户端指向BFF的代理端点,所有流量通过BFF转发:
import { HubConnectionBuilder } from '@microsoft/signalr'; // 配置BFF的代理端点作为Hub地址 const connection = new HubConnectionBuilder() .withUrl('/api/chathub/negotiate') // 替换为你的BFF实际端点路径 .build(); // 启动连接 connection.start() .then(() => console.log('通过BFF连接SignalR Hub成功')) .catch(err => console.error('连接失败:', err));
为什么重定向方案不可行?
SignalR客户端在初始化时会固化你传入的Hub URL,协商请求的重定向仅影响单次请求的响应结果,但客户端不会自动将后续的WebSocket/长轮询请求切换到新的地址。代理转发方案则让BFF处理鉴权逻辑,对客户端完全透明,客户端只需与BFF通信,由BFF负责和SignalR Hub交互。
内容的提问来源于stack exchange,提问作者Szyszka947
相关产品推荐
相关产品推荐

