SignalR报错‘无法在非Connected状态发送数据’的原因排查
本地Vue3前端连接ASP.NET SignalR Hub时出现连接未就绪错误
我在本地尝试用运行于https://localhost:3000/的Vue 3前端,连接运行于https://localhost:7001/的ASP.NET后端SignalR Hub。此前已解决CORS配置问题,但现在出现错误:
Error: Cannot send data if the connection is not in the 'Connected' State.
以下是相关配置及代码:
CORS配置
builder.Services.AddCors(options => { options.AddPolicy("AllowAllOrigins", builder => { builder.AllowCredentials() .WithOrigins( "https://localhost:3000/","https://localhost:7001/","/","localhost") .SetIsOriginAllowedToAllowWildcardSubdomains() .AllowAnyHeader() .AllowAnyMethod(); }); }); builder.Services.AddSignalR(); builder.Services.AddControllersWithViews(); builder.Services.AddSpaStaticFiles(configuration => { configuration.RootPath = "ClientApp/dist"; }); var app = builder.Build(); app.UseCors("AllowAllOrigins"); app.UseRouting(); app.MapHub<ChatHub>("/chat");
Vite代理配置
import { fileURLToPath, URL } from 'url' import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import vuetify from 'vite-plugin-vuetify' import { readFileSync } from 'fs' import { join } from 'path' export default defineConfig({ plugins: [ vue({ template: { compilerOptions: { isCustomElement: (tag) => ['md-linedivider'].includes(tag), }, }, }), vuetify(), ], resolve: { alias: { '@': fileURLToPath(new URL('./src', import.meta.url)), }, }, server: { proxy: { '/api': { target: 'https://localhost:7001', secure: false, ws: false, }, '/ws': { target: 'http://localhost:7001', ws: true, changeOrigin: true, secure: true, }, }, https: { cert: readFileSync(certFilePath), key: readFileSync(keyFilePath), }, watch: { usePolling: true, }, }, })
Vue组件代码
<template> <div> <input v-model="message" type="text" placeholder="Message" /> <button @click="sendMessage">Send</button> <ul> <li v-for="message in messages" :key="message.id">{{ message.text }}</li> </ul> </div> </template> <script> import { ref, onMounted } from 'vue' import * as signalR from '@microsoft/signalr' export default { setup() { const message = ref('') const messages = ref([]) const connection = new signalR.HubConnectionBuilder() .withUrl('https://localhost:3000/ws/chat') .build() connection.on('Receive', (message) => { messages.value.push({ id: Date.now(), text: message }) }) onMounted(async () => { try { await connection.start() } catch (err) { console.error(err) } }) const sendMessage = () => { if (message.value) { connection.invoke('Send', message.value) message.value = '' } } return { message, messages, sendMessage, } }, } </script>
SignalR Hub代码
using Microsoft.AspNetCore.SignalR; using System.Threading.Tasks; namespace ChatHubSpace { public class ChatHub : Hub { public async Task Send(string message) { await this.Clients.All.SendAsync("Receive", message); } } }
可能的错误原因
- 代理协议不匹配:Vite代理中
/ws的target使用http://localhost:7001,但前端是https协议,若后端实际运行在https下,协议不一致会直接导致连接失败。应将target改为https://localhost:7001。 - 连接未就绪时触发发送:
onMounted中启动连接是异步操作,若用户在连接尚未成功建立时点击发送按钮,就会触发该错误。需在发送前检查连接状态:const sendMessage = () => { if (message.value && connection.state === signalR.HubConnectionState.Connected) { connection.invoke('Send', message.value) message.value = '' } } - 代理secure设置矛盾:
/ws代理中secure: true但target是http,这会导致证书验证失败。若后端用http,需将secure设为false;若后端用https,则修改target为https并保持secure: true。 - CORS配置无效源干扰:
WithOrigins中的"/"和"localhost"属于无效源,可能引发配置冲突,应仅保留明确的"https://localhost:3000"和"https://localhost:7001"。
内容的提问来源于stack exchange,提问作者Chamyyys
相关产品推荐
相关产品推荐

