Vue+TS+SignalR连接ASP.NET Core后端失败,CORS预检请求报错
SignalR聊天功能CORS预检重定向错误问题
技术栈
- 前端:Vue + TypeScript + @microsoft/signalr
- 后端:C# + ASP.NET Core + Docker
后端Program.cs代码
using DomovoiBackend.API.Auth.ServiceDecorators; using DomovoiBackend.API.Controllers; using DomovoiBackend.API.JsonInheritance; using DomovoiBackend.Application; using DomovoiBackend.Application.Services.CounterAgentServices.Interfaces; using DomovoiBackend.Persistence; using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Cors.Infrastructure; using Microsoft.OpenApi.Models; var builder = WebApplication.CreateBuilder(args); builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSignalR(); builder.Services.AddSwaggerGen(options => { options.SwaggerDoc("v1", new OpenApiInfo() { Title = "DomovoiBackend.API", Version = "v1" }); options.UseAllOfToExtendReferenceSchemas(); options.UseAllOfForInheritance(); options.UseOneOfForPolymorphism(); }); var inheritanceConfigurations = new AssemblyInheritanceConfiguration() .CreateAllConfigurations(); builder.Services.AddControllers().AddNewtonsoftJson( options => { foreach(var inheritanceConfiguration in inheritanceConfigurations) options.SerializerSettings.Converters.Add(inheritanceConfiguration); }); builder.Services.AddApplicationLayer() .AddMappers() .AddPersistence(builder.Configuration) .CreateDatabase() .FillDatabase(); builder.Services.Decorate<ICounterAgentService, AuthCounterAgentService>(); builder.Services.AddHttpContextAccessor(); builder.Services.AddDistributedMemoryCache(); builder.Services.AddAuthorization(); builder.Services.AddSession(); builder.Services.AddCors(); builder.Services .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.ExpireTimeSpan = TimeSpan.FromMinutes(30); options.SlidingExpiration = true; options.LoginPath = "/CounterAgent/Login"; options.Cookie.SecurePolicy = CookieSecurePolicy.Always; options.Cookie.SameSite = SameSiteMode.Strict; }); builder.Services.AddAuthorizationBuilder() .AddPolicy("AuthenticatedCounterAgent", policy => policy.RequireClaim("CounterAgentId")); var app = builder.Build(); app.UseAuthentication(); app.UseAuthorization(); app.UseSession(); app.UseCors(policyBuilder => { policyBuilder.WithOrigins("http://localhost:5173") .AllowAnyHeader() .AllowAnyMethod() .AllowCredentials() .SetIsOriginAllowedToAllowWildcardSubdomains() .SetIsOriginAllowed((host) => true); }); app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.MapHub<ChatHub>("/chat"); app.Run(); public partial class Program;
ChatHub类代码
[Authorize] public class ChatHub : Hub { [Authorize] public async Task Send(string message, string idReceiver) { var nameSender = Context.User?.Identity?.Name; if (Clients.User(idReceiver) == null) throw new UnknownUser($"User with id \"{idReceiver}\" does not exist in the system"); await Clients.User(idReceiver).SendAsync("Receive", message, nameSender); await Clients.Caller.SendAsync("NotifySendMethod", "Ok"); } }
前端ChatService代码
import { HttpTransportType, HubConnection, HubConnectionBuilder } from "@microsoft/signalr"; import { inject, singleton } from "tsyringe"; import { Chat } from "../../application/useCases/chat"; import { Message } from "../../domain/chat/message"; import { MessageStatus } from "../../domain/enums/chatEnum"; import { CounterAgent } from "../../domain/counteragents/counteragent"; import { CounteragentViewModel } from "../../viewModel/CounteragentViewModel"; import { ICouterAgentMapper } from "../../mappers/interfaces/couteragentMapperInterface"; @singleton() export class ChatService { private readonly _connection: HubConnection; private _listener!: Chat; public constructor(@inject("chatURL") private readonly _baseURL: string, @inject("ICouterAgentMapper") private readonly _userMapper: ICouterAgentMapper) { this._connection = new HubConnectionBuilder() .withUrl(this._baseURL, { headers: { 'Access-Control-Allow-Origin': '*', }, withCredentials: true, transport: HttpTransportType.WebSockets, }) .build(); this._connection.on("Receive", (text: string, idSender: string) => this.receiveMessage(text, idSender)); } public start(idCompanion :string, user: CounteragentViewModel): void { let counteragent = this._userMapper.mapViewModelToCouterAget(user); this._listener = new Chat(this, true, idCompanion, counteragent); this._connection.start(); } public close(): void { this._connection.stop() } public get state(): string { return this._connection.state.toString(); } public get messages(): Message[] { return this._listener.messages; } public async sendMessage(text: string): Promise<void> { let message = new Message("", text, this._listener.idCompanion, this._listener.user.id!); try { let response = await this._connection.invoke("Send", message.text, message.recieverId); message.status = MessageStatus.Send; } catch(e){ message.status = MessageStatus.NotSend; throw(e); } finally { this._listener.addMessage(message); } } public receiveMessage(text: string, idSender: string): void { let message = new Message("", text, idSender, this._listener.user.id!); message.status = MessageStatus.Recieve; this._listener.addMessage(message); } }
Vue组件ChatView.vue使用代码
//... export default defineComponent({ components: { Header}, data() { return { store: store, chatService: {} as ChatService, //... }; }, computed: { }, mounted() { //... this.load_data(); }, methods: { load_data(){ let chatService = container.resolve(ChatService); this.chatService = chatService; chatService.start(this.user.id, this.store.state.user!); this.messages = this.chatService.messages; }, //... }, }) </script>
报错信息
从源'http://localhost:5173'访问'http://localhost:8181/chat/negotiate?negotiateVersion=1'时被CORS策略阻止:预检请求的响应未通过访问控制检查:不允许对预检请求进行重定向。
@microsoft_signalr.js?v=12bba02c:2110 Uncaught (in promise) Error: 无法完成与服务器的协商:TypeError: Failed to fetch
at HttpConnection._getNegotiationResponse
(@microsoft_signalr.js?v=12bba02c:2110:29)ChatService.ts:35 [2024-06-03T18:17:15.726Z] Error: 无法启动连接:Error: 无法完成与服务器的协商:TypeError: Failed to fetch
ChatService.ts:35 [2024-06-03T18:17:15.725Z] Error: 无法完成与服务器的协商:TypeError: Failed to fetch
已尝试调整后端CORS策略设置和前端connectionBuilder.WithUrl中的请求头,均未解决问题。
内容的提问来源于stack exchange,提问作者Malakia
相关产品推荐
相关产品推荐

