0

在我的 Angular 应用程序中,当我登录应用程序时,我会获得一个访问令牌,我需要在其他组件(不是父/子关系)的 API 调用中使用它。我尝试使用共享服务,但它不起作用

数据服务:

import { Injectable } from '@angular/core';
import { Subject }    from 'rxjs/Subject';

@Injectable()
export class DataService {

  private userInfo = new Subject<any>();
  currentuserInfo$ = this.userInfo.asObservable();

  constructor() { }

  updateUserInfo(message: any) {
    this.userInfo.next(message)
  }

}

在我的登录组件中,我有

this.dataService.updateUserInfo(data.userToken);

其他组件

this.dataService.currentuserInfo$.subscribe((data: any) => { 
  console.log(data);
});

在这里,我无法获取使用登录组件更新的令牌。

在共享服务中,我尝试了主题和行为主题,但都没有工作。

我确保我只是在 app.module.ts 中提到了这个 DataService 作为提供者。我没有在登录组件或任何其他组件中提到它

4

3 回答 3

0

在请求中添加令牌的最佳方法是使用拦截器

import { Injectable, Injector, EventEmitter } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { AuthService } from '../services/auth.service';

@Injectable()
export class HttpsRequestInterceptor implements HttpInterceptor {
    private actionUrl: string;

    constructor(
        private injector: Injector
    ) {
        this.actionUrl = 'https://test.com/dev';
    }


    intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        const _req = {
            url: this.actionUrl + req.url,
            headers: req.headers.set('Content-Type', 'application/json')
        };

        const user = this.injector.get(AuthService).getAuthenticatedUser();

        if (user) {
            user.getSession((err: any, session: any) => {
                if (session) {
                    const token = session.getIdToken().getJwtToken();
                    _req.headers = req.headers
                        .set('Content-Type', 'application/json')
                        .set('Authorization', token);
                }
            });
        }

        return next.handle(req.clone(_req));
    }
}

更新:

如果您需要创建可共享的服务 - 您可以尝试使用行为主题。请看这个例子

更新2:

如果您想在页面刷新的情况下使用可共享数据 - 您应该使用 localstorage:

localStorage.setItem('str', 'whatever string'); // set string
localStorage.setItem('obj', JSON.stringify(obj)); // set object
const str = localStorage.getItem('str'); // get string
const obj = JSON.parse(localStorage.getItem('obj')); // get object
const str = localStorage.removeItem('str'); // remove 
于 2018-04-17T20:12:42.187 回答
0

您能否展示您是如何使用 BahviorSubject 并解释这不起作用的含义?我认为它应该工作。

首先,您需要在服务中的某处声明它,例如

token: BegaviorSubject<type> = new BehaviorSubject(null);

然后在您收到该令牌的地方,您需要设置下一个

this.token.next(receivedToken);

最后,从其他组件订阅它

this.yourService.token.subscribe(token => {
   this.token = token;
}

如果您有一些错误,请显示它。

于 2018-04-17T20:25:26.380 回答
0

@indira:正如@JB Nizet 解释的那样,在页面刷新时,您的整个应用程序都会刷新,因此您的主题中包含的任何内容都将丢失!

现在,一个简单的主题也应该在你的情况下工作,你是否在一个肯定被调用的函数中订阅了主题?例如里面ngOnInit()

ngOnInit() {
    this.dataService.currentuserInfo$.subscribe((data) => {
      console.log("data subscribed", data);
    })
}

我在我的机器上试过,上面的工作正常。

为什么主题不工作?

Simple 失败的一个可能原因Subject是:您只是在测试 Subject 的功能,而不是进行实际登录。在您的场景中,您的login组件在实际完成订阅的其他组件之前加载。但是请稍等:如果您在订阅之前已经向 Subject 推送了新数据,您将无法获取订阅中的数据。只有在 next 之后this.dataService.updateUserInfo(data.userToken),您才会获得 Subscription 中的值。如果是这种情况,那么您绝对可以使用BehaviorSubject.

就保存主题的状态而言,您有如下选项:cookies, localstorage.

例如:当您从登录组件更新主题时,将数据存储在localstorage

this.dataService.updateUserInfo(data.userToken)
localStorage.setItem('serviceData', String(data.userToken));

然后除了在你的其他组件中监听 Subject 之外,你还可以localStorage.getItem('serviceData')ngOnInit()

我自己更喜欢 localStorage 而不是 cookie。Cookie 对每个域都有大小和数量限制。有关更多信息,请参阅此链接。甚至localStorage有大小限制,但那是巨大的。从这个SO question中也可以清楚地使用 cookie 或 localStorage 。您可以分析您的需求并实施其中任何一个。

于 2018-04-17T20:52:48.043 回答