您必须让所有到“页面”的路由都通过以让您的 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 以导航到其他地方,它仍然会触发服务器调用和完全重新加载,理想情况下不会出现这种情况,但我会说这是一个非常微不足道的问题。