在我的角应用程序中,当我登录应用程序时,我获得了一个访问令牌,我需要在其他组件的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);
});
这里我无法获得使用登录组件更新的tocken。
在共享服务中,我尝试了主题和行为主题,但两者都没有效果。
我确保我只是在app.module.ts中提到这个DataService作为提供者。我在登录组件或任何其他组件中没有提到它
答案 0 :(得分: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));
}
}
<强>更新:强>
如果您需要创建可共享的服务 - 您可以尝试使用行为主题。请查看此example
<强> UPDATED2:强>
如果您想在不刷新页面的情况下使用可共享数据 - 您应该使用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
答案 1 :(得分:0)
你能说明你如何使用BahviorSubject并解释这是什么意思吗?我认为它应该有用。
首先,您需要在服务中的某个位置声明它,例如
token: BegaviorSubject<type> = new BehaviorSubject(null);
然后在某个地方收到该令牌,您需要设置下一个
this.token.next(receivedToken);
最后,订阅其他组件
this.yourService.token.subscribe(token => {
this.token = token;
}
如果您有任何错误,请展示。
答案 2 :(得分:0)
@indira:正如@JB Nizet解释的那样,在页面刷新时,您的整个应用程序都会刷新,因此您的主题中包含的任何内容都将丢失!
现在,一个简单的主题也应该在你的情况下工作,你在一个明确调用的函数中订阅主题吗?例如在ngOnInit()
ngOnInit() {
this.dataService.currentuserInfo$.subscribe((data) => {
console.log("data subscribed", data);
})
}
我在我的机器上试过,上面的工作正常。
为什么主题不起作用?
简单Subject
失败的可能原因可能是:
您只是测试主题的功能而不是进行实际登录。在您的方案中,您的login
组件在实际完成订阅的其他组件之前加载。但是等一下:如果您在订阅之前已经将新数据推送到主题,那么您将无法获得订阅中的数据。只有在下一个this.dataService.updateUserInfo(data.userToken)
之后,您才会获得订阅中的值。如果是这种情况,那么您绝对可以使用BehaviorSubject
。
就保存主题的状态而言,您有以下选项:cookies
,localstorage
。
例如:当您从登录组件更新主题时,将数据存储在localstorage
中:
this.dataService.updateUserInfo(data.userToken)
localStorage.setItem('serviceData', String(data.userToken));
然后,除了在其他组件中收听主题外,您还可以在localStorage.getItem('serviceData')
ngOnInit()
的值
我自己更喜欢localStorage而不是cookies。 Cookie具有每个域的大小和数量限制。见this link for more info。即使localStorage
有一个大小限制,但这是巨大的。使用cookies或localStorage也可以清楚地看出SO question.您可以分析您的需求并实施其中任何一个。