vuejs 历史模式路由问题与路由参数,asp.net 核心和 SignalR 后端

vuejs history mode routing issue with routing parameters, asp.net core and SignalR backend

我正在使用带有 vue-router 和 SignalR ASP.NET 核心后端的 VueJS 前端。

现在我希望能够让我的客户连接到一个房间,并将数据仅发送给该组的成员。我通过在后端使用两种方法来做到这一点,一种是创建一个房间并向它们发送一个 12char 长的随机生成的字符串,该字符串存储在内存中,另一种是加入一个组,发送这些字符串之一作为 Join Room 方法的参数。现在,这工作正常,但我还希望能够通过附加到 url 的组 ID 字符串加入 link。那将是 myurl.com/room/:groupId,我计划通过路由到同一组件来实现,但在后一种情况下,有一个带有 url 参数 :groupId 的道具集。这确实有效,并且在您通常输入此 groupId 的对话框中,它会正确显示。

无论如何,当导航到 myurl.com/room/:groupId 时,我确实在 DevTools 中收到以下错误消息: 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 的问题:

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 协商失败,因为响应是 text/html 而不是 text/json?如果是这样,那么为什么当我导航到 url myurl.com/room 而没有附加 groupId 时协商不会失败?它使用相同的回退 await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));?请注意,两条路径都路由到我前端中完全相同的组件,只是 URL 中带有 groupId 的路径将其作为道具传递,因此将其设置为默认值。

这里是组件的代码。

<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 设置:

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;

希望我没有遗漏任何重要信息。如果我这样做了,请打电话给我,非常感谢你的任何回应,我已经非常感激能够指出正确的方向,因为我什至不知道它是路由器问题还是信号器问题。

如果有人想深入了解,我会将 github link 都留给 frontend and backend

出现这种情况的原因是,我的 SignalR 集线器的路径是“/drafthub”。 由于某种原因,转到前端路径“/room”(没有附加“/”)会将协商请求发送到正确的路径,无论如何,只要我有“/room/”,它就会将它发送到路径“ /room/drafthub”,服务器用我的默认 404 回退响应,我的 index.html 然后使用客户端路由。所以本质上,它服务了两次,一次是在我输入 URL 时,另一次是在我尝试升级到 signalR 连接时。

FIX:

我仍在尝试弄清楚究竟是什么将其映射到“/room/drafthub”,但现在我也只是将 Drafthub 映射到后端 ConfigureServices 方法中的那个端点,如下所示:

app.UseEndpoints(endpoints =>
      {
        endpoints.MapHub<DraftHub>("/drafthub");
        endpoints.MapHub<DraftHub>("/room/drafthub");
      });