【问题标题】:Using Router in services in Angular 4在 Angular 4 的服务中使用路由器
【发布时间】:2017-11-03 14:41:55
【问题描述】:

我已经使用 Angular 2/4 大约一年了,我不断回到这个困境,是否将路由器注入服务是否可以被视为一种不好的做法?

这是更多的架构问题。我相信没有确切的答案,但我想听听你的意见。所以这里有两个例子。

  1. 考虑下一个代码。想象一下,我们有一些组件,我们想在某些操作后将用户重定向到特定的路线,例如用户添加了一个新实体,我们希望将他重定向回网格。

component.ts

constructor(private router: Router) {}

someAction() {
  // Some code here
  this.router.navigate(['/grid']);
}

这里我觉得用Router就很好了,因为Router和Component都是UI层。

  1. 现在假设我们有auth.service.ts,它负责身份验证。我们希望能够将用户从应用程序中注销,我们有 logout() 函数可以做到这一点。

auth.service.ts

constructor(private router: Router) {}

logout() {
  // Cleanup token, storage, etc.
  this.router.navigate(['/login']);
}

所以从架构上思考:

  1. 您如何看待服务内的这种路由器使用情况?
  2. 您认为这是一种有效的方法吗?
  3. 如果不是,在这种情况下您有什么建议?

我正在考虑将 eventEmitter 放在 authService 上并在 app.component.ts 中订阅它,但仍然不确定它是否比在服务中更好。

对于这种情况,我很感激任何 cmets。非常感谢!

编辑

另一个例子:UI 是一个带有任务的日历。

有一项服务可以处理所有数据流并为日历提供数据。日历本身并不要求提供数据,而是从服务订阅数据更改。

现在我需要将用户路由到与此日历不同的屏幕。想象一下用户在下周/月/年点击。

此数据存储在路由 URL 中,因此用户可以在页面刷新后停留在同一天,但日历组件不知道天/周/月。

它们被封装在服务中。那么在这种情况下你会使用路由器吗?

【问题讨论】:

  • 关于您的最后一个示例,用户如何访问事件详细信息或从日历导航?询问互动
  • 在我的例子中,他点击了这一天并希望获得这一天的具体细分。在组件内部,我在服务上调用 fetchDay()。所以基本上我要求服务获取数据但同时我需要将用户重定向到下一个屏幕,但要计算路线我需要来自服务的封装数据:)
  • 您可以在订阅中完成这项工作吗?在 fetchDay() 上,这里的故事是,给定页面呈现您的日历,该日历在调用服务以获取数据的组件中具有初始化逻辑,一旦数据已成功处理,您始终可以从组件路由日历。
  • 是的,我相信。这正是两难境地。在组件中订阅和重定向或从服务重定向。我想我会做第一个变种。在我看来,它在架构上仍然更正确。感谢您的意见!
  • 最好从组件中进行,因为您可以看到活动部件在哪里,无论在服务中是否可以完成,但很难识别,因为您总是会先检查组件。

标签: angular


【解决方案1】:

TL;DR:从组件开始总是更好,因为您可以看到移动部件在哪里,无论在服务中可以完成,但很难识别,因为您总是首先检查组件.


您可以为此目的使用 Guards 和拦截器,我添加了如下所示的错误拦截器,以便在收到 401 时路由到注销:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpErrorResponse, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(private router: Router) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).catch(
      (err: HttpErrorResponse) => {
        if (this.router.url !== '/login' && err.status === 401) {
          this.router.navigate(['/logout']);
        }
        return Observable.throw(err);
      }
    );
  }
}

在您的 app.module 中提供它,或者在我的情况下,我为所有单例创建了一个 core.module 以保持我的 app.module 的清洁

{
  provide: HTTP_INTERCEPTORS,
  useClass: ErrorInterceptor,
  multi: true
}

有了这样的东西,您不必将路由放入服务中,当令牌无效时,您将从您的 api 获得 401。

您可能需要稍微编写一下这段代码,尽量保持通用。

【讨论】:

  • 感谢您的回答!是的,这看起来很有希望。但是在这种情况下,您需要等待下一个响应才能让用户离开系统进入登录页面。我正在考虑立即的事情。就像您在用户菜单中单击注销一样。也许这不是最好的例子。一般的问题是你认为将路由器注入服务是不好的做法吗?
  • 我一直在做的是我在模板中有一个按钮/链接,用于注销。注销是一个调用 auth 服务并终止会话的组件(假设用户想要注销)
  • 明白。再次感谢!是的,我通常也是这样做的。我想我需要用一个不同的例子来编辑我原来的问题。
  • 添加更多,我们可以从那里开始
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-19
  • 1970-01-01
  • 2017-11-01
  • 2018-04-09
相关资源
最近更新 更多