22

Angular 2 beta 默认使用 html5 路由。但是,当您转到一个组件并且路由更改(例如http://localhost:5000/aboutus)并且您重新加载/刷新页面时,没有加载任何内容。

这篇文章中也提出了这个问题。大多数答案都说,如果我们要在 Angular 2 中追求 HTML5 路由,那么应该在服务器端处理这个路由问题。更多讨论在这里

我不确定如何使用 asp.net 服务器环境来处理这个问题。

任何 angular 2 开发人员也使用 asp.net 并遇到此问题?

PS。我正在使用 ASP.NET 5。我的 Angular 2 路由正在使用 MVC 路由。

4

11 回答 11

19

您看到的问题与客户端上的 Angular 路由和 MVC 服务器端路由之间的区别有关。您实际上得到了一个404 Page Not Found错误,因为服务器没有该路由的控制器和操作。我怀疑你没有处理错误,这就是为什么它看起来好像什么也没发生。

当您重新加载http://localhost:5000/aboutus或尝试直接从快捷方式链接到该 URL 或通过在地址栏中键入它(深度链接)时,它会向服务器发送请求。ASP.NET MVC 将尝试解析该路由,在您的情况下,它将尝试加载aboutusController并运行该Index操作。当然,这不是你想要的,因为你的aboutus路由是一个 Angular 组件。

您应该做的是为 ASP.NET MVC 路由器创建一种方法,以将应该由 Angular 解析的 URL 传递回客户端。

在您的Startup.cs文件中,在Configure()方法中,将“spa-fallback”路由添加到现有路由:

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

    // when the user types in a link handled by client side routing to the address bar 
    // or refreshes the page, that triggers the server routing. The server should pass 
    // that onto the client, so Angular can handle the route
    routes.MapRoute(
        name: "spa-fallback",
        template: "{*url}",
        defaults: new { controller = "Home", action = "Index" }
    );
});

通过创建一个指向最终加载 Angular 应用程序的控制器和视图的包罗万象的路由,这将允许将服务器未处理的 URL 传递到客户端以进行正确的路由。

于 2016-03-16T19:16:25.340 回答
8

在您Startup.cs将其添加到Configure方法中。这必须在其他app语句之前。

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

    if (context.Response.StatusCode == 404 && !Path.HasExtension(context.Request.Path.Value)) {
        context.Request.Path = "/index.html"; // Put your Angular root page here 
        await next();
    }
});
于 2016-06-10T06:42:33.840 回答
6

我最喜欢的解决方案是将以下代码添加到 Global.asax.cs 中,它可以非常顺利且可靠地解决该问题:

     private const string RootUrl = "~/Home/Index";
     // You can replace "~Home/Index" with whatever holds your app selector (<my-app></my-app>)
     // such as RootUrl="index.html" or any controller action or browsable route

     protected void Application_BeginRequest(Object sender, EventArgs e)
        {
            // Gets incoming request path
            var path = Request.Url.AbsolutePath;

            // To allow access to api via url during testing (if you're using api controllers) - you may want to remove this in production unless you wish to grant direct access to api calls from client...
            var isApi = path.StartsWith("/api", StringComparison.InvariantCultureIgnoreCase);
            // To allow access to my .net MVCController for login
            var isAccount = path.StartsWith("/account", StringComparison.InvariantCultureIgnoreCase);
            if (isApi || isAccount)
            {
                return;
            }

            // Redirects to the RootUrl you specified above if the server can't find anything else
            if (!System.IO.File.Exists(Context.Server.MapPath(path)))
                Context.RewritePath(RootUrl);
        }
于 2016-08-04T23:51:47.217 回答
5

您需要在 ASP.NET MVC 中使用此路由

app.UseMvc(routes =>
{
     routes.MapRoute("Default", "{*url}",  new { @controller = "App", @action = "Index" });
});

然后您需要使用 basePath 选项设置 SystemJS

于 2016-03-11T15:07:36.707 回答
2

您正在寻找的功能是 URL 重写。有两种可能的方法来处理它。经典的方法是让 IIS 完成工作,如下所述:

https://stackoverflow.com/a/25955654/3207433

如果您不想依赖 IIS,则可以改为在 ASP.NET 5 中间件中处理此问题,如我在此处的回答所示:

https://stackoverflow.com/a/34882405/3207433

于 2016-01-19T16:58:00.283 回答
2

我没有运气

 routes.MapRoute("Default", "{*url}",  
                  new { @controller = "App", @action = "RedirectIndex" });

去工作。我仍然得到带有任何客户端路由的 404。

更新:
弄清楚为什么包罗万象的路由不起作用:我定义了一个属性路由([Route("api/RedirectIndex")]),虽然可以使用后备路由直接访问普通路由,但它没有触发。删除属性路由使其工作。

另一个似乎与包罗万象的路由处理程序一样简单的解决方案是创建一个自定义处理程序,该处理程序在中间件管道的末尾触发Configure()

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");

});

//handle client side routes
app.Run( async (context) =>
{
        context.Response.ContentType = "text/html";
        await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,"index.html"));

});

如果没有其他处理程序接收该请求,这基本上最终成为一个包罗万象的路由,它只是通过现有的 URL 请求将 index.html 发送出去。

即使与IIS 重写规则结合使用也能很好地工作(在这种情况下,上述内容永远不会被解雇。

写了一篇关于这个主题的博客文章:

于 2017-08-07T07:39:30.390 回答
1

这里有两个解决这个问题的选项。您可以将哈希位置策略添加到您的应用程序模块。

import { LocationStrategy, HashLocationStrategy } from '@angular/common';

@NgModule({
imports: [.... ],
declarations: [...],
bootstrap: [AppComponent],
providers: [
{
  provide: LocationStrategy,
  useClass: HashLocationStrategy
}
]
})
export class AppModule { }

此选项仅适用于位于 Home ASP 控制器上的 Angular2 应用程序部分

您的第二个选择是将路由添加到与您的 Angular 2 应用程序路由匹配的 ASP 控制器并返回“索引”视图

public class HomeController : Controller
{
    public IActionResult Index()
    {
        return View();
    }

    [ActionName("Angular-Route1")]
    public IActionResult AngularRoute1()
    {
        return View("Index");
    }

    public IActionResult Route2()
    {
        return View("Index");
    }
}
于 2017-03-02T14:13:34.483 回答
0

你用过:

指令:组件中的[RouterOutlet,RouterLink]。

于 2016-01-06T21:39:39.873 回答
0

应用@ZOXEXIVO 的解决方案,然后在您的 _Layout.cshtml 中添加:

<head>
    <base href="/"/>
    .....
</had>
于 2016-04-18T14:43:21.287 回答
0

当您从角度路由调用 Home/Index 时,您可以同时使用这两种路由。

Home/Index.cshtml
<my-app></my-app>

app.routing.ts
    const routes: Routes = [
        { path: '', redirectTo: '/Home/Index', pathMatch: 'full' },
        { path: 'Home/Index', component: DashboardComponent }
    ]

所以当 URL 为 Home/Index 时将加载活动 url 的组件,因此它将加载仪表板组件。

于 2016-10-25T06:53:30.853 回答
0

上面选择的解决方案对我不起作用我也得到了 404 在关注 T 的所有评论后。我在 MVC5 应用程序中使用 angular5 应用程序。我使用默认的索引登录页面作为 angular5 的开始。我的 Angular 应用程序位于名为 mvcroot/ClientApp/ 的文件夹中,但在 ng build 上,它通过使用“outDir”更改 .angular-cli.json 文件中的一项设置将分布式文件放入 mvcroot/Dist/ 中:“../Dist”

这个解决方案确实有效。

这样,只有 Dist 目录中的路由会失败。现在,您可以每次都点击刷新,并在保持正确组件的同时重新加载 angular5 应用程序的准确路径。一定要把所有的东西放在第一位。附带说明一下,如果在 angular5 中使用令牌身份验证,请将令牌保存到 window.localStorage(或 angular5 应用程序之外的其他机制),因为点击刷新将清除您可能将令牌存储在全局变量中的所有内存. 这使用户在刷新时不必再次登录。

routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

            routes.MapRoute(
                "Catch All",
                "dist/{*url}",
            new { controller = "Home", action = "Index", id = UrlParameter.Optional });

            routes.MapRoute(
                name: "Default",
                url: "{controller}/{action}/{id}",
                defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }


            );
于 2018-04-20T21:32:42.283 回答