【问题标题】:MVC6 routing to single-page application without losing 404MVC6路由到单页应用不丢404
【发布时间】:2016-02-20 19:17:00
【问题描述】:

我正在用 angular2 和 MVC5 编写一个单页应用程序。不过,我对这两者都是新手,而且我在路由方面遇到了问题。

我想将 URL 匹配为:

  • / -> 转到我的索引页面,它引导 angular
  • /api/{controller}/{id?} -> REST API
  • /{*anythingelse} -> 如果那里存在文件,则将其作为静态内容返回;否则,如果角度可以路由它,则有角度路由它;否则返回 404。

第二点很简单,如果我愿意放弃 404 返回,我可以让客户端路由正常工作,但我似乎无法调和这一切。

看来这应该可行:

app.UseStaticFiles();
app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "api",
        template: "api/{controller}/{id?}");
    routes.MapRoute(
        name: "spa",
        template: "{*anythingelse}",
        defaults: new { controller = "Home", action = "Index" });
});

和:

@RouteConfig([
    { path: "/", name: 'Splash', component: SplashView },
    { path: '/accounts/login', name: 'Login', component: LoginView },
    { path: '/accounts/register', name: 'Registration', component: RegistrationView },
    { path: '/home/...', name: 'Home', component: HomeView },
])

但这只是为每个不是静态文件的请求提供 Index.cshtml。

我觉得这一定是一个已解决的问题,但我无法在网上找到任何关于它的信息。如何正确地做到这一点?

我使用“HTML5”样式的路径而不是哈希样式。

【问题讨论】:

  • 你的 REST api 使用 WebApi 吗? WebApi 是一个独立于 MVC 的框架,并且有自己独立的路由配置。如果使用 MVC(不是 WebApi),您没有正确配置它 - 您需要提供默认操作 defaults: new { action = "Index" } 或 URL 中的操作 api/{controller}/{action}/{id?}
  • 另外,您对路线顺序的假设是不可能的。 Angular 在浏览器中运行,因此它会首先路由。否则,它将按照您在服务器端配置它们的确切顺序尝试您配置的路由。一旦请求到达服务器,您就无法再次将控制权交还给 Angular。
  • 啊,抱歉。我放下了 MVC5,但实际上是指 ASP.NET 5 上的 MVC6。在 ASP.NET 5 中,WebAPI 和 MVC 路由器已合并。
  • From-Angular 导航应该不是问题,因为我只提供对现有页面的导航,因此不需要 404。我主要关注用户的情况直接输入一个URI。服务器在那里获得了第一次破解,如果它知道客户端将接受哪些 URI,则可以返回 404。也许我可以通过某种方式告诉服务器。

标签: asp.net-core-mvc angular2-routing


【解决方案1】:

所以有两种方法可以做到这一点。如果您使用的是 HashLocationStrategy,我强烈建议您在服务器端执行此操作,因为我发现它更容易处理。

否则,您可以创建自己的 RouterOutlet 组件来处理异常。我不是 100% 清楚你如何让它与你的 RouterConfig 一起工作,因为我没有深入研究路由方面,但我敢打赌你可以看看是否存在路由然后去那里,否则会出现 404 错误。这是我的代码,用于查看用户是否使用 Json Web 令牌登录。

import {Directive, Attribute, ElementRef, DynamicComponentLoader} from 'angular2/core';
import {Router, RouterOutlet, ComponentInstruction} from 'angular2/router';

@Directive({
  selector: 'router-outlet'
})
export class LoggedInRouterOutlet extends RouterOutlet {
  publicRoutes: any;
  private parentRouter: Router;

  constructor(_elementRef: ElementRef, _loader: DynamicComponentLoader,
              _parentRouter: Router, @Attribute('name') nameAttr: string) {
    super(_elementRef, _loader, _parentRouter, nameAttr);

    this.parentRouter = _parentRouter;

  }

  activate(instruction: ComponentInstruction) {

    if (!localStorage.getItem('jwt') || !tokenNotExpired('jwt')) {//Public Routes does not work with Hash Location Strategy, need to come up with something else.
      // todo: redirect to Login, may be there is a better way?
      if(localStorage.getItem('jwt')){
        localStorage.removeItem('jwt');
      }
      this.parentRouter.navigate(['Login']);
    }
    return super.activate(instruction);
  }
}

如您所见,我负责检查令牌,如果他们没有令牌,他们只能进入我的登录页面。然后在您的 app.component 或您的引导组件中,只需将其用作您的路由器插座,而不是原来的。

很抱歉,我无法提供更多帮助,但我希望这能让您指明正确的方向!

【讨论】:

  • 也许我只是太密集了,但我不明白你是如何从被覆盖的 RouterOutlet(客户端)到 404(服务器端)的。
  • 所以我想向您展示的是您可以处理具有相同功能的if does not exist in RouterConfig route 404,因为收到的每个 url 都将通过您的新路由器插座并进行检查.
  • 您是否在谈论仅“404”的未找到页面?我正在寻找来自 Web 服务器的实际 404 HTTP 响应代码。
  • 哦,好的。我可能会看看 Angular2 的服务器端渲染。我没有深入研究它,但是您可以只处理 404 服务器端,然后将其发送到 angular。
【解决方案2】:

我认为您正在寻找正则表达式路由约束:

routes.MapRoute("app", "{*anything}", 
    new { controller = "Home", action = "Index" }, 
    new {anything = new RegexRouteConstraint("^(?!api\\/).+") });

这将阻止您的 catch all 路由映射到以“api/”开头的任何请求

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-10-20
    • 2013-08-12
    • 1970-01-01
    • 2020-12-13
    • 1970-01-01
    • 2019-05-11
    • 2015-10-09
    相关资源
    最近更新 更多