2

我打算用 asp.net MVC4 构建一个 SPA,但由于路由,我不太确定如何设置我的项目。例如,大多数 SPA 都使用这样的哈希路由mypage/#/News/today

mypage/News/today如果我没有指定带有操作的Controller命名,如果直接浏览会发生什么?Newstoday

该应用程序应该处理这两种类型的路由,我该如何实现呢?

我是否必须以经典方式构建我的应用程序,例如添加具有适当操作和视图的多个控制器,以及构建带有敲除、jquery 等的客户端 MVC 结构?

4

1 回答 1

1

您必须让所有到“页面”的路由都通过以让您的 SPA 处理它们(如果不是到您的 SPA 中的真实页面,则基本上包括假 404),但同时,需要确保您得到API 调用和/或文件请求的正确响应。

下面是我的设置(我使用 Vue 作为 js 框架,但这并不重要,对于服务器端的部分来说根本不重要)。

首先,将其添加到您的 Startup.cs,除了您的默认路由设置:

    public void Configure(IApplicationBuilder app, IHostingEnvironment env)
    {
        ...

        app.Use(async (context, next) =>
        {
            await next();

            var path = context.Request.Path.Value;
            // If there's no available file and the request doesn't contain an extension, we're probably trying to access a page
            if (context.Response.StatusCode == (int)HttpStatusCode.NotFound && !Path.HasExtension(path) && !path.StartsWith("/api"))
            {
                context.Request.Path = "/Home/SpaRedirect"; // attempts to redirect to the URL within the SPA
                context.Response.StatusCode = (int)HttpStatusCode.OK; // Make sure we update the status code, otherwise it returns 404
                await next();
            }
        });

        ...
    }

所以新添加的 SpaRedirect 到 HomeController 看起来是这样的,只是将请求的 URL 存储在 ViewData 中......

    public IActionResult SpaRedirect()
    {
        ViewData["RequestUrl"] = HttpContext.Request.Path;
        return View("Index");
    }

然后在 Index.cshtml 中,只需在会话存储中捕获请求的 url,这样我们就可以在客户端使用它:

<script src="~/dist/main.js" asp-append-version="true">
    sessionStorage.setItem("redirectAttempt", @ViewData["RequestUrl"]);
</script>

然后在您的启动脚本文件(您的 SPA 的入口点)中,添加如下内容:

let redirectAttemptUrl = sessionStorage.getItem("redirectAttempt");
if (redirectAttemptUrl) {
    router.push(redirectAttemptUrl);
    sessionStorage.removeItem("redirectAttempt");
}

它只是检查是否存在请求的 url,然后 SPA 的路由器尝试导航到它(在上面的示例中,它是一个 vue 路由器),然后将其从存储中删除。

因此,如果用户尝试通过在 url 栏中(或通过书签)输入 URL 来直接导航到 URL,应用程序将加载并将它们带到正确的位置,如果它存在......这会将我们带到最后一块...

最后,您必须在您的 SPA 中处理“404s”,这是通过向您的路由定义中添加一条包罗万象的路由来完成的,该路由将用户带到您设置的 404 组件页面,对于 Vue,它看起来像这样:

// adding an explicit 404 path as well for programmatically handling when something is not found within the app, i.e. return this.$router.push('/404')
{ path: '/404', component: NotFound, name: '404', alias: '*' }, // remove alias to not show the actual url that resulted in our little 404 here
{ path: '*', redirect: '/404' }, // this is the catch-all path to take us to our 404 page

警告:我不是专家,所以可能会遗漏一些东西,希望能就如何改进这一点提供更多评论。这不能处理的一件事是,如果用户已经在 SPA 中并且出于某种原因直接编辑 URL 以导航到其他地方,它仍然会触发服务器调用和完全重新加载,理想情况下不会出现这种情况,但我会说这是一个非常微不足道的问题。

于 2018-12-27T06:03:03.543 回答