指向特定 Angular 2.0 SPA 状态的外部链接不起作用

Posted

技术标签:

【中文标题】指向特定 Angular 2.0 SPA 状态的外部链接不起作用【英文标题】:External links into specific Angular 2.0 SPA states don't work 【发布时间】:2017-03-22 07:00:39 【问题描述】:

我正在使用 AngularJS 2.4.6、Typescript 2.1.2、IIS 8.0、Chrome、Visual Studio 2015

我正在使用 Angular Heroes 教程,并注意到当我刷新浏览器时,我得到了 404 响应(由于 PathLocationStrategy -aka html5 路径 - 默认使用)...所以这是有道理的,因为 IIS 看不到 /dashboard返回。

有很多使用 URL 重写的解决方案,我这样做了,并且确实正确地路由到了 index.html。

我的问题是,当我刷新浏览器时,我希望它处于与之前相同的状态。这与 angular 1.5 一样使用哈希策略运行良好。

我需要做一些特定的事情来创建这种行为吗?与原样(Angular 2.0)一样,刷新最终导致显示基本状态,而不是我所在的状态。

我注意到重写操作将 301 发送回浏览器,因此 index.html 也不知道预期的状态。

重要的是,指向 Angular 2 应用特定状态的外部链接(例如,来自电子邮件)如何工作?

例如,如果我发送一封电子邮件,其中包含指向我的应用的链接,例如:https://myserver/some/path/to/aState

从我尝试过的所有内容来看,这个简单的场景似乎都不适用于 IIS。

本项目不涉及 MVC。客户端代码向 webapi 中间层 web 发出 ajax 请求,但就我所问的目的而言,您可以假设根本没有 http 调用。

【问题讨论】:

这仅适用于 Angular2(HashLocationStrategyPathLocationStrategy) 很难在没有看到任何代码的情况下判断您的应用程序中出了什么问题。您是在根路径还是子目录中提供应用程序? 我不确定在这种情况下要显示什么作为代码。据我所知,我的 OP 中的链接会得到 404。 【参考方案1】:

您是否尝试过使用哈希策略?

RouterModule.forRoot(appRoutes,  useHash: true )

【讨论】:

谷歌推荐我相信的路径策略。我们在 Angular 1.x 中使用散列,但我们想转向使用路径策略。 出于调试目的仍然值得尝试。如果它有效,这是 HTML5 pushState 的服务器端问题。 我希望哈希策略在这种情况下有效。但是作为路由器路径的静态链接呢? IIS 基本上不知道它是有效的路由器路径并响应 404 对吗?我只是认为这会相当直截了当,但也许不是? 它只需要返回index.html未知的URL。 IIS 会为图像、css、tec 执行此操作,我认为有效的路由器路径仍会导致 IIS 返回 index.html,但实际上并没有进入正确的状态,对吗?【参考方案2】:

我假设您在 Visual Studio 2015 上使用 ASP.NET MVC 和解决方案根目录中的 index.html 开发解决方案,文件/文件夹结构至少如下:

- /Controllers
- index.html
- /src/app/ (Angular source)
- web.config

第一步:web.config配置

将以下 rewrite rules 添加到 web.config 的 system.webServer 部分:

<system.webServer>
  <rewrite>
    <rules>
      <rule name="clientRewrite rule" stopProcessing="true">
        <match url=".*" />
        <conditions logicalGrouping="MatchAll">
          <add input="REQUEST_URI" matchType="Pattern" pattern="^/api/" ignoreCase="true" negate="true" />      
          <add input="REQUEST_FILENAME" matchType="IsFile" negate="true" />
          <add input="REQUEST_URI" matchType="Pattern" pattern="^/assets/" ignoreCase="true" negate="true" />
        </conditions>
        <action type="Rewrite" url="/" />
      </rule>
    </rules>
  </rewrite>
</system.webServer>

此配置会将所有请求(/api 和 /assets 除外)重定向到您的 index.html。您可以自定义此行为。

另外,不要忘记在appSettings 中启用webpages

<add key="webpages:Enabled" value="false" />

编辑

system.web`编译`部分中为html 扩展添加buildProviders

<buildProviders>
  <add extension=".html" type="System.Web.WebPages.Razor.RazorBuildProvider, System.Web.WebPages.Razor" />
</buildProviders>

第 2 步:index.html

确保在 index.html 中包含base href,位于&lt;head&gt; ... &lt;/head&gt; 标记之间:

<base href="/">

第 3 步:Global.asax 配置

您需要注册html 分机。只需将以下方法添加到 Global.asax.cs:

public static void RegisterHtmlExtension()

    RazorCodeLanguage.Languages.Add("html", new CSharpRazorCodeLanguage());
    WebPageHttpHandler.RegisterExtension("html");

并在Application_Start() 方法中调用RegisterHtmlExtension();

您无需为angular views(模板)注册路由。以下(最小)服务器路由配置就足够了:

public static void RegisterRoutes(RouteCollection routes)

    routes.IgnoreRoute("favicon.ico");
    routes.IgnoreRoute("resource.axd/*pathInfo");

    //register custom routes (extensions, etc)
    var routePublisher = EngineContext.Current.Resolve<IRoutePublisher>();
    routePublisher.RegisterRoutes(routes);

如果您有 WebAPI 控制器,您可能需要为它们进行适当的路由配置。此配置应该可以工作:

public static class WebApiRouteProvider

    public static void Register(HttpConfiguration config)
    
        // Web API routes
        config.MapHttpAttributeRoutes();

        config.Routes.MapHttpRoute(
            "DefaultApi",
            "api/controller/id",
            new  area = "api", id = RouteParameter.Optional 
        );
    

而且,您必须通过在Application_Start() 方法中调用GlobalConfiguration.Configure(WebApiRouteProvider.Register); 来注册这些路由。

结论

这样,您将能够将所有请求重定向到您的 index.html(重写规则中明确定义的路径除外)。

而且,Angular 将能够拦截具有给定路径的所有请求(例如:http://yoursite.com/about/us、http://yoursite.com/account/login 等),这将导致呈现具有给定路由的组件。

【讨论】:

我正在通过 Angular 的 http 模块访问 webapi 中间层,与背面的 mvc 非常相似(但在这种情况下,我的 Visual Studio 项目中当然没有 Controller 文件夹,只是转译了 js 和 html -中间层是它自己的使用 C#/webapi 的网络)。抱歉耽搁了,我正在审核您的其余答案。 真的,在这种情况下,MVC 不是考虑因素。如果有人点击example.com/apath/dashboard 之类的链接,它将显示 404。如果我通过example.com 访问应用程序,一切都很好,然后我可以通过路由器路由到仪表板,但如果我点击刷新,我会得到 404。 我假设我想要任何对存在的 html、css、图像文件的请求以返回该项目。任何请求都是正确解析的有效路由器路径,以及任何不是默认/路由到我的登录组件的有效路由器路径的路径。 IIS 会将有效和无效的路由器路径都视为 404 情况。 如果您说您可以通过example.com 浏览应用程序,则表示您的默认文档是INDEX.HTML,并且已正确解析。同时,我通过在您的web.config. 中添加buildProviders 部分来编辑答案 只是想确定一下,您是否在&lt;head&gt; ... &lt;/head&gt; 标签之间添加了&lt;base href="/"&gt;&lt;base href="/index.html"&gt;

以上是关于指向特定 Angular 2.0 SPA 状态的外部链接不起作用的主要内容,如果未能解决你的问题,请参考以下文章

在 aspnet 核心 SPA Angular 应用程序中返回 404 状态代码

ASP.NET 4.5 Web API 2.0,JWT 消息处理程序将状态 0 返回到 Angular 7 HTTP 拦截器

将特定的外键字段指定为 SSAS 数据源中两个表之间的链接

是否可以将单个MVC剃刀视图/页面转换为SPA?

SPA 应该在哪里保存 OAuth 2.0 访问令牌?

vue 2.0 和 vue-router 2.0 构建 SPA,router-view 没有更新