问题描述
我正在使用带有 vue-router 的 VueJS 前端和 SignalR ASP.NET Core 后端.
I am using a VueJS frontend with vue-router and a SignalR ASP.NET Core backend.
现在我希望能够让我的客户连接到一个房间,并将数据仅发送给该组的成员.我通过在后端使用两种方法来做到这一点,一种是创建一个房间并向它们发送存储在内存中的 12 个字符长的随机生成的字符串,或者通过加入一个组,将这些字符串之一作为 Join Room 方法的参数发送.现在,这工作正常,但我还希望能够通过附加到 url 的组 ID 字符串的链接加入.那将是 myurl.com/room/:groupId
,我计划通过路由到相同的组件来实现,但在后一种情况下有一个带有 url 参数 :groupId
.这确实有效,并且在您通常输入此 groupId 的对话框中,它会正确显示.
Now i want the ability to have my Clients connect to a room, and send data to only members of that group. I do that by with two methods on my backend, one to create a room and send them a 12char long randomly generated string stored in-memory, or by joining a group, sending one of these strings as parameter for the Join Room method. Now, this works fine but i also want the ability to join over a link with the group ID string appended to the url. That would be myurl.com/room/:groupId
which i planned to implement by routing to the same component but in the latter case having a prop set with the url paramter :groupId
. This does work and in the dialog where you usually enter this groupId, it is correctly displayed.
无论如何,当导航到 myurl.com/room/:groupId
时,我确实在 DevTools 中收到以下错误消息:错误:无法完成与服务器的协商:SyntaxError:JSON.parse:JSON 数据的第 1 行第 1 列出现意外字符
Anyhow, i do get the following error messages in DevTools when navigating to myurl.com/room/:groupId
:Error: Failed to complete negotiation with the server: SyntaxError: JSON.parse: unexpected character at line 1 column 1 of the JSON data
现在我认为这与我的后端配置有关,在我的 Startup.cs 中,我已从某处粘贴此代码以规避在不是/"的每个路径上获取 404 的问题:
Now i think that has something to do with my backend configuration, inside my Startup.cs, i have pasted this code from somewhere to circumvent the problem with getting 404s on every path that isnt "/":
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseEndpoints(endpoints =>
{
Console.WriteLine(endpoints.ToString());
Console.WriteLine("^^^^^^^^^^^^^^^^^^^^^^");
endpoints.MapHub<DraftHub>("/drafthub");
});
//this function right here is what i mean, it sends index.html after assembling the path with vue-router i suppose?
app.Run( async (context) =>
{
context.Response.ContentType = "text/html";
await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));
});
}
所以我想知道,这个错误是否意味着 SignalR 协商失败,因为 resposne 是 text/html 而不是 text/json?如果是这种情况,那么当我导航到没有附加 groupId 的 url myurl.com/room
时,为什么协商不会失败?它使用相同的回退 await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));
?请注意,两个路径都路由到我前端的完全相同的组件,只有 URL 中具有 groupId 的路径将其作为 prop 传递,因此将其设置为默认值.
So i am wondering, does that error mean, that the SignalR negotiation is failing because the resposne is text/html and not text/json? If that were the case, then why does the negotiation not fail when i navigate to the url myurl.com/room
without the groupId appended to it? it uses the same fallback await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));
? Note that both paths are routing to the exact same Component in my frontend, just the one with the groupId in the URL passes it as a prop and therefore sets it as a default value.
这里是组件的代码.
<template>
<base-view>
<join-dialog
v-model="visible"
:login-info.sync="loginInfo"
@click:create="createRoom"
@click:join="joinRoom"
/>
<chat-sidebar
:users="connectionInfo.groupConnections"
:my-name="loginInfo.userName"
:user="loginInfo.userName"
:group-id="connectionInfo.groupId"
/>
</base-view>
</template>
<script lang="ts">
import { defineComponent, ref, Ref } from "@vue/composition-api";
import JoinDialog from "@/components/JoinDialog.vue";
import ChatSidebar from "@/components/ChatSidebar.vue";
import ChessBoard from "@/components/Chess/ChessBoard.vue";
import {
sendCreateRoom,
onUpdateRoom,
ConnectionInfo,
sendJoinRoom,
start,
} from "@/service/signalr/draftHub";
import { createLoginInfo } from "../service/models";
export default defineComponent({
components: {
JoinDialog,
ChatSidebar,
ChessBoard,
},
props: {
groupId: { // THIS HERE IS SET WHEN URL HAS GROUP ID IN IT.
type: String,
default: () => "",
},
},
setup(props) {
const visible = ref(true);
const loginInfo = ref(createLoginInfo());
loginInfo.value.groupId = props.groupId; //ALREADY SET THE GROUP ID INCASE IT WAS IN THE URL
const connectionInfo: Ref<ConnectionInfo> = ref({});
const createRoom = () => {
sendCreateRoom(loginInfo.value.userName).then(
() => (visible.value = false)
);
};
const joinRoom = () => {
sendJoinRoom(loginInfo.value).then(() => (visible.value = false));
};
onUpdateRoom((connInfo: ConnectionInfo) => {
connectionInfo.value = connInfo;
console.log("running handler now to update users", connInfo);
});
start().then(() => console.log("connected to drafthub"));
return {
visible,
createRoom,
joinRoom,
loginInfo,
connectionInfo,
};
},
});
</script>
<style scoped></style>
这里是我的 vue-router 设置:
And here, my vue-router Setup:
import Vue from "vue";
import VueRouter, { RouteConfig } from "vue-router";
import Home from "../views/Home.vue";
import PrivateRoom from "../views/PrivateRoom.vue";
Vue.use(VueRouter);
const routes: Array<RouteConfig> = [
{
path: "/",
name: "Home",
component: Home,
},
{
path: "/about",
name: "About",
// route level code-splitting
// this generates a separate chunk (about.[hash].js) for this route
// which is lazy-loaded when the route is visited.
component: () =>
import(/* webpackChunkName: "about" */ "../views/About.vue"),
},
{
path: "/room",
name: "PrivateRoom",
component: PrivateRoom,
},
{
path: "/room/:groupId",
name: "PrivateRoomInstance",
component: PrivateRoom,
props: true,
},
];
const router = new VueRouter({
mode: "history",
base: process.env.BASE_URL,
routes,
});
export default router;
我希望我没有遗漏任何重要信息.如果我这样做了,请给我打电话,非常感谢您的任何回应,我已经非常感激能指出正确的方向,因为我什至不知道是路由器问题还是信号器问题问题.
I hope i did not leave out any important information. Please call me out if i did so and thank you very much for any kind of response, i would already be more than grateful to just be pointed in the correct direction, since i dont even have a clue if its a router issue or a signalr issue.
如果有人想深入了解,我会将两个 github 链接都留给 前端和后端
In case anyone wants to take a deeper look i will leave both of the github links, to the frontend and backend
推荐答案
所以出现这种情况的原因是,我的 SignalR 集线器的路径是/drafthub".由于某种原因,转到前端路径/room"(没有附加/")会将协商请求发送到正确的路径,无论如何,只要我有/room/",它就会将其发送到路径"/room/drafthub",服务器用我的默认 404 回退响应,我的 index.html 然后使用客户端路由.所以本质上,它提供了两次服务,一次是在我输入 URL 时,另一次是在我尝试升级到 signalR 连接时.
So the reason for this appearing was, the path for my SignalR hub was, "/drafthub".For some reason going to the frontent path "/room" (without appended "/") would send the negotiation request to the correct path, anyhow, as soon as i had "/room/", it would send it to the path "/room/drafthub", which the server responded with my default 404 fallback, my index.html which then used clientside routing. So in essence, it served that twice, once when i typed in the URL, and another time when i tried to upgrade to the signalR connection.
修复:
我仍在尝试弄清楚到底是什么将它映射到/room/drafthub",但现在我只是在后端的 ConfigureServices
方法中将 Drafthub 映射到该端点,如下所示:
i am still trying to figure out what exactly maps this to "/room/drafthub" but for now i just also mapped the Drafthub to that endpoint in the ConfigureServices
Method in my backend like this:
app.UseEndpoints(endpoints =>
{
endpoints.MapHub<DraftHub>("/drafthub");
endpoints.MapHub<DraftHub>("/room/drafthub");
});
这篇关于带有路由参数、asp.net 核心和 SignalR 后端的 vuejs 历史模式路由问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!