在利用由Angular,React,Vue等运用程序框架构建的客户端运用程序时,您总是会处理HTML5客户端路由,它将完备在浏览器中处理到页面和组件的客户端路由。
险些完备在浏览器中...

HTML5客户端路由在客户端上事情的很好,但是当深入链接到一个站点或在浏览器中按刷新时,客户端路由有一个恶习,变成做事器HTTP要求。
要求可能未配置做事器的路由。

在这篇文章中,我将谈论如何使ASP.NET Core(或间接ASP.NET运用程序)通过有效地将客户端运用程序重新连接到其路由来处理这些“假”要求。

aspnethtml5实例处置ASPNET Core中的HTML5客户端路由回退 GraphQL

Html 5客户端路由?

如果您不知道HTML5客户端路由是什么,请快速回顾一下。

客户端框架实现他们自己的客户端路由机制,以便他们可以 - 就像做事器运用程序 - 在页面或组件之间进行导航。

Angular支持几种路由类型:

哈希路线(http:// localhost:4200 /#!
/ albums或http:// localhost:4200 /#/ albums)

HTML 5路线(http:// localhost:4200 / albums)

#!/ 哈希邦德路线

前者是一种较早的方法,它直接与HTTP语义一起事情,指定任何具有a的URL #在客户端被触发并跳转到页面内的“本地”URL。
框架可以拦截导航并检讨跟随的URL内容#以确定路线。
散列爆炸#!\用于区分运用程序URL和普通#锚链接。

散列爆炸路线的好处是,他们只是事情。
没有做事器端出血的路线,如果您书签或刷新客户端页面,它只是如预期的那样事情,由于散列逻辑是作为浏览器中本地URL解析的一部分实行的。
很大略,对吧?它只是事情。

但缺陷是,如果您必须手动输入网址,则这些网址非常丢脸且不直不雅观。
对付散列爆炸路线来说,这并不是一个很好的论据,但是不管它们是否对HTML5路由不利。

哈希在Angular中的Bang路由

Angular利用默认的HTML5客户端路由,但它是一个大略的开关来启用Hashbang路由,而不是HTML5路由::

// in app.module.tsproviders : [ .. // make sure you use this for Hash Urls rather than HTML 5 routing { provide: LocationStrategy, useClass: HashLocationStrategy },]

只要您routerLink在HTML模板中利用链接网址,并router.navigate()代码链接中利用,Angular交流机就会自动在两种模式之间进行切换。

在HTML中利用<a routerLink=\公众/albums\公众 />链接

在代码中利用: router.navigate([\"大众/album\"大众,album.id])

HTML5路由

HTML5路由利用更繁芜的方法 - 它利用HTML5的Pushstate API来掌握客户真个路由并管理地址栏显示。

这种方法的优点是,利用HTML5 API相对随意马虎操作,并且利用标准的无延伸路由约定,利用Web运用程序和API时,URL更加简洁,易于掌握。

但是HTML5路由须要做事器的明确支持来精确理解哪些路由是做事器路由,哪些是客户路由。

没有做事器处理的HTML5路由问题

问题在于HTML5客户端路由与做事器路由无法区分。

http://localhost:4200/albums可以很随意马虎地将客户端URL作为做事器端URL。
在完备在客户端上导航时,HTML5路线事情正常 - 运用程序可以拦截导航并在激活特定路线时路由到相应的客户端页面。

如果您利用深层链接导航到客户端驱动的运用程序,然后您将该页面书签为书签,然后利用该URL导航回到该页面,或者刷新当前活动页面,则会弹出问题。
在这两种情形下,当浏览器要求路由时,客户端运用程序不运行,因此浏览器向做事器要求路由URL。
但是,默认情形下不设置处理说/albums路线,以是你会得到一个缺点。

如果您在ASP.NET Core运用程序中没有对HTML5路由设置进行任何分外处理,您将在运用程序中打开缺点页面,或者从Kestrel中选择此默认显示:

图1 - 未处理的客户端路由产生做事器缺点

修复做事器上的客户端路由

那么你如何办理这个问题呢?

客户端SPA运用程序常日有一个或几个启动运用程序的静态页面。
对付一个范例的Angular运用程序,该页面是index.html启动运用程序并启动客户端路由。
大多数框架都足够聪明,可以在启动时检讨当前路由,并移至首次访问要求的路由。

如果客户端路由从书签,链接或完备刷新被触发到做事器,则须要供应index.html并保持原始URL不变。

然后,客户端运用程序将自行勾引,并且内部路由启动,以希望将您甩回书签/刷新位置。

从做事器供应Index.html

为了这个事情,你须要确保做事器只供应做事器卖力的内容。

有几种方法可以做到这一点:

主机做事器URL重写

处理ASP.NET Core运用程序中的客户端路由

主机Web做事器上的URL重写

如果您在主流Web做事器上运行ASP.NET Core(或ASP.NET)运用程序,最大略且最有效的办理方案是重写客户端URL并为index.html给定的URL 供应内容。

在IIS上,您可以利用IIS重写模块来实行此操作。
我最近在一篇博文中更详细地先容了这一点:

ASP.NET核心运用程序的IIS重写规则

但是这里是干系的IIS重写规则:

<rewrite> <rules> <!-- Make sure you have a <base href=\公众/\"大众 /> tag to fix the root path or all relative links will break on rewrite --><rule name=\"大众AngularJS-Html5-Routes\"大众 stopProcessing=\"大众true\"大众> <match url=\公众.\"大众 /> <conditions logicalGrouping=\公众MatchAll\"大众> <add input=\"大众{REQUEST_FILENAME}\公众 matchType=\"大众IsFile\"大众 negate=\"大众true\公众 /> <add input=\"大众{REQUEST_FILENAME}\公众 matchType=\"大众IsDirectory\公众 negate=\公众true\公众 /> <add input=\公众{REQUEST_URI}\"大众 pattern=\公众api/\"大众 negate=\"大众true\公众 /> </conditions> <action type=\"大众Rewrite\公众 url=\"大众wwwroot/index.html\公众 /> </rule> </rules></rewrite>

您可以从以下任何位置安装UrlRewrite模块:

Microsoft下载网站

choco install urlrewrite

Web平台安装程序

如果你在Linux上运行Docker和nginX或者Apache,那么类似的Rewrite选项就可以在那里利用。

让ASP.NET Core处理客户端路由

如前所述,我常日利用像IIS或nginX这样的前端Web做事器来处理重定向,但是常日在测试或内部运用程序时,只须要Kestrel直接为运用程序供应做事即可。
如果您直接让Kestrel处理HTTP流量,那么您须要在ASP.NET Core代码中处理客户端路由。

捕获所有app.Run()处理程序

有很多方法可用,但是我创造了在Startup类的Configure()方法中利用一个非常大略的后备处理程序来处理客户端路由的最大略的方法:

// set up whatever routes you use with UseMvc()// you may not need to set up any routes here// if you only use attribute routes!app.UseMvc(routes =>{ routes.MapRoute( name: \公众default\公众, template: \"大众{controller=Home}/{action=Index}/{id?}\"大众);});//handle client side routesapp.Run( async (context) =>{ context.Response.ContentType = \公众text/html\"大众; await context.Response.SendFileAsync(Path.Combine(env.WebRootPath,\公众index.html\公众));});

关键是app.Run()位于路由后的管道末端的中间件处理程序。
如果做事器端路由不能找到匹配的路由,这个通用途理程序就会启动。

上面的代码是你可以做的最大略的事情,只是把内容发送index.html到客户端。
如果您有多个静态页面和SPA筒仓,您可以在个中添加额外的逻辑来考试测验确定须要加载哪个页面。

请把稳,内容不会重定向到,而是作为内嵌流发送到现有的URL要求,以便用户要求的URL保持不变。
这确保了当用户要求http://localhost:4200/albums你回到那个客户端页面而不是index.html

捕获所有路由处理程序

另一种方法是在路由定义中利用末了定义的全部捕获的 MVC路由处理程序。
这基本上拿起你的MVC路由配置无法处理的任何URL,然后路由到你指定的路线。

利用catch-all处理程序设置您的MVC路线,将此代码放在您的Startup类的Configure()方法中:

app.UseMvc(routes =>{ // default routes plus any other custom routesroutes.MapRoute(name: \"大众default\"大众,template: \公众{controller=Home}/{action=Index}/{id?}\"大众); // Catch all Route - catches anything not caught be other routesroutes.MapRoute(name: \"大众catch-all\公众,template: \公众{url}\"大众,defaults: new {controller = \公众AlbumViewerApi\"大众, action = \公众RedirectIndex\"大众});});

然后实行完备相同的事情中间件处理程序利用:index.html利用以下代码将内容流式传输到客户端:

// we need hosting environment for base pathpublic IHostingEnvironment HostingEnv { get; }public AlbumViewerApiController(IHostingEnvironment env){ HostingEnv = env;}[HttpGet]public IActionResult RedirectIndex(){ return new PhysicalFileResult( Path.Combine(HostingEnv.WebRootPath,\公众index.html\公众), new MediaTypeHeaderValue(\公众text/html\"大众) );}

Catch-All Route不该用属性路由

确保您为回退路线指定的路线不具有分配给它的属性路线。
当我昨天检讨出来的时候,我无法得到一条全面的路线,直到我[Route(\"大众api/RedirectIndex\"大众)]从掌握器的操作中移除 了这个全部事情。

SpaServices

SpaServices供应了另一个选项,routes.MapSpaFallbackRoute()只管我自己也没有考试测验过,但是如果您已经在ASP.NET Core运用程序中利用了Spa做事,那么这可能是一个大略的方法来实现这个功能,包括潜在的支持做事器预渲染。

概要

HTML5路由为客户端运用程序供应了干净的URL,但它的价格必须有做事器支持才能使其事情。
利用主机Web做事器中的重写规则或直接在Kestrel的中间件管道或自定义路由处理程序中进行设置并不困难,但是您必须确保将此功能显式添加到您创建的每个ASP.NET运用程序中。

只管旧的Hash Bang路线看起来不那么干净,但它们事情正常,不须要任何做事器端支持。
对付须要支持古代浏览器的非公众年夜众运用程序或运用程序,在没有做事器支持的情形下,散列邦线路仍旧是供应路由的可行办法。

末了,如果您正在利用完全的Web做事器,UrlRewriting是处理非ASP.NET内核后端直接处理的非API内容的最干净和最有效的办法。

选择是好的,你有几个选择供应方便,干净的网址或大略的只是把它放在功能。
你的选择...