如何将 Ionic 数据存储与 BehaviorSubject 和 Observable 一起使用
How to use Ionic Data Storage with BehaviorSubject and Observable
我正在尝试使用 Angular 9 / Ionic 5
创建应用
我正在使用 Ionic Data Storage
所以,我的 auth.service.ts 看起来像:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Storage } from '@ionic/storage'
import { BehaviorSubject, Observable, from } from 'rxjs'
@Injectable({
providedIn: 'root'
})
export class AuthService {
private currentTokenSubject: BehaviorSubject<string>
public currentToken: Observable<string>
constructor(
private http: HttpClient,
private storage: Storage,
) {
this.getToken()
.then(res => {
this.currentTokenSubject = new BehaviorSubject(res)
this.currentToken = this.currentTokenSubject.asObservable()
}
)
}
async getToken() {
return await this.storage.get('accessToken')
}
public get currentTokenValue(): string {
return this.currentTokenSubject.value;
}
login(username: string, password: string) {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
})
return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, { }, { headers })
.pipe(map((res: Token) => {
let token = res.token
// store user details and jwt token in local storage to keep user logged in between page refreshes
this.storage.set('accessToken', token);
return token;
}));
}
logout() {
// remove user from local storage to log user out
this.storage.remove('accessToken');
this.currentTokenSubject.next(null);
}
}
和jwt.interceptor.ts看起来像:
import { Injectable } from '@angular/core'
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'
import { Observable } from 'rxjs'
import { AuthService } from '@app/_services'
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(
private authService: AuthService
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
const currentToken = this.authService.currentTokenValue;
if (currentToken) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentToken}`
}
});
}
return next.handle(request);
}
}
因此,当我尝试调用服务时,出现错误,因为 Ionic Storage returns Observable:
Error: Uncaught (in promise): TypeError: Cannot read property 'value' of undefined
TypeError: Cannot read property 'value' of undefined
at AuthService.get currentTokenValue [as currentTokenValue] (auth.service.ts:39)
问题是:从 Ionic Storage 中获取价值并使用它的正确方法是什么?
您试图在 BehaviorSubject
的 value
getter 分配任何值之前访问该问题。最好避免 value
getter 并订阅 observable 以保持异步。尝试以下
auth.service.ts
export class AuthService {
private currentTokenSubject = new BehaviorSubject<string>(null); // <-- assign default value here
constructor(
private http: HttpClient,
private storage: Storage,
) {
this.getToken().then(
res => {
this.currentTokenSubject.next(res); // <-- push token to the observable
}
);
}
async getToken() {
return await this.storage.get('accessToken');
}
public get currentTokenValue(): Observable < string > {
return this.currentTokenSubject.asObservable(); // <-- return observable here
}
login(username: string, password: string) {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
})
return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, {}, { headers }).pipe(
map((res: Token) => {
let token = res.token;
// store user details and jwt token in local storage to keep user logged in between page refreshes
this.storage.set('accessToken', token);
this.currentTokenSubject.next(token); // <-- also push new token here?
return token;
}));
}
logout() {
// remove user from local storage to log user out
this.storage.remove('accessToken');
this.currentTokenSubject.next(null);
}
}
现在您需要订阅currentTokenValue()
函数才能取回令牌。
一些component/service
export class SomeComponent implements OnInit {
token: string;
ngOnInit() {
this.authService.currentTokenValue().subscribe(
token => {
if(token) { // <-- check if token valid because it can also be null
this.token = token;
}
}
);
}
}
我正在尝试使用 Angular 9 / Ionic 5
创建应用我正在使用 Ionic Data Storage
所以,我的 auth.service.ts 看起来像:
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Storage } from '@ionic/storage'
import { BehaviorSubject, Observable, from } from 'rxjs'
@Injectable({
providedIn: 'root'
})
export class AuthService {
private currentTokenSubject: BehaviorSubject<string>
public currentToken: Observable<string>
constructor(
private http: HttpClient,
private storage: Storage,
) {
this.getToken()
.then(res => {
this.currentTokenSubject = new BehaviorSubject(res)
this.currentToken = this.currentTokenSubject.asObservable()
}
)
}
async getToken() {
return await this.storage.get('accessToken')
}
public get currentTokenValue(): string {
return this.currentTokenSubject.value;
}
login(username: string, password: string) {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
})
return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, { }, { headers })
.pipe(map((res: Token) => {
let token = res.token
// store user details and jwt token in local storage to keep user logged in between page refreshes
this.storage.set('accessToken', token);
return token;
}));
}
logout() {
// remove user from local storage to log user out
this.storage.remove('accessToken');
this.currentTokenSubject.next(null);
}
}
和jwt.interceptor.ts看起来像:
import { Injectable } from '@angular/core'
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'
import { Observable } from 'rxjs'
import { AuthService } from '@app/_services'
@Injectable()
export class JwtInterceptor implements HttpInterceptor {
constructor(
private authService: AuthService
) { }
intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
// add authorization header with jwt token if available
const currentToken = this.authService.currentTokenValue;
if (currentToken) {
request = request.clone({
setHeaders: {
Authorization: `Bearer ${currentToken}`
}
});
}
return next.handle(request);
}
}
因此,当我尝试调用服务时,出现错误,因为 Ionic Storage returns Observable:
Error: Uncaught (in promise): TypeError: Cannot read property 'value' of undefined
TypeError: Cannot read property 'value' of undefined
at AuthService.get currentTokenValue [as currentTokenValue] (auth.service.ts:39)
问题是:从 Ionic Storage 中获取价值并使用它的正确方法是什么?
您试图在 BehaviorSubject
的 value
getter 分配任何值之前访问该问题。最好避免 value
getter 并订阅 observable 以保持异步。尝试以下
auth.service.ts
export class AuthService {
private currentTokenSubject = new BehaviorSubject<string>(null); // <-- assign default value here
constructor(
private http: HttpClient,
private storage: Storage,
) {
this.getToken().then(
res => {
this.currentTokenSubject.next(res); // <-- push token to the observable
}
);
}
async getToken() {
return await this.storage.get('accessToken');
}
public get currentTokenValue(): Observable < string > {
return this.currentTokenSubject.asObservable(); // <-- return observable here
}
login(username: string, password: string) {
const headers = new HttpHeaders({
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Basic ' + btoa(username + ':' + unescape(encodeURIComponent(password)))
})
return this.http.post<Token>(`${environment.apiUrl}/auth/signin`, {}, { headers }).pipe(
map((res: Token) => {
let token = res.token;
// store user details and jwt token in local storage to keep user logged in between page refreshes
this.storage.set('accessToken', token);
this.currentTokenSubject.next(token); // <-- also push new token here?
return token;
}));
}
logout() {
// remove user from local storage to log user out
this.storage.remove('accessToken');
this.currentTokenSubject.next(null);
}
}
现在您需要订阅currentTokenValue()
函数才能取回令牌。
一些component/service
export class SomeComponent implements OnInit {
token: string;
ngOnInit() {
this.authService.currentTokenValue().subscribe(
token => {
if(token) { // <-- check if token valid because it can also be null
this.token = token;
}
}
);
}
}