将 observable 延迟到 return 值,直到我在 angular 5 中从我的 HTTP 请求中获得结果
delay observable to return value until i get result from my HTTP request in angular 5
我想将 observable 延迟到 return 值,直到我从订阅中的 HTTP 请求中得到 new_token。我也在用延迟时间,但我无法成功。
Error: returning undefined value
Expected: new_token returned from server
refreshToken(): Observable<string> {
const token_refreshed = localStorage.getItem("refresh_token");
let new_token: string;
if (token_refreshed) {
console.log("this refreshed token" + token_refreshed);
const headers = new HttpHeaders({
'Authorization': "Basic " + btoa("clientId:client-secret"),
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'refresh_token',
'refresh_token': token_refreshed
});
var creds = "grant_type=refresh_token" + "&credentials=true" + "&refresh_token=" + token_refreshed;
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers })
.subscribe(response => {
localStorage.setItem('access_token', response.access_token);
new_token = response.access_token;
}, err => {
console.log("User authentication failed!");
});
}
console.log('i am returning');
return Observable.of(new_token).delay(3000);
}
更新:正在消耗的方法refresh_token,我正在使用拦截器,401 方法在下面
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
console.log('I am handler 401');
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.tokenSubject.next(null);
return this.authService.refreshToken()
.switchMap((newToken: string) => {
console.log('map token' + newToken);
//I'm getting null new token here from authService.refreshToken()
if (newToken) {
this.tokenSubject.next(newToken);
return next.handle(this.addToken(req, newToken));
}
return this.logoutUser();
})
.catch(error => {
console.log('bad news its catch');
return this.logoutUser();
})
.finally(() => {
this.isRefreshingToken = false;
});
} else {
return this.tokenSubject
.filter(token => token != null)
.take(1)
.switchMap(token => {
console.log('i am switch map else ');
return next.handle(this.addToken(req, token));
});
}
}
不要订阅 post
请求,如果您想执行某些 side-effects 请求,请改用 do
运算符。
if (token_refreshed) {
return this.httplclient.post(...)
.do(response => {
localStorage...
})
.map(response => ...) // map the response to return only the new token?
.delay(3000); // or maybe you don't need this?
}
return Observable.of(new_token).delay(3000);
你不需要延迟。只要值可用就传递它,因为您无法确定该值在 3000 毫秒后是否可用。
refreshToken(): Observable<string> {
const tokenObsr = new Subject<string>();
const token_refreshed = localStorage.getItem("refresh_token");
if (token_refreshed) {
console.log("this refreshed token" + token_refreshed);
const headers = new HttpHeaders({
'Authorization': "Basic " + btoa("clientId:client-secret"),
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'refresh_token',
'refresh_token': token_refreshed
});
var creds = "grant_type=refresh_token" + "&credentials=true" + "&refresh_token=" + token_refreshed;
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers })
.subscribe(response => {
localStorage.setItem('access_token', response.access_token);
tokenObsr.next(response.access_token);
}, err => {
console.log("User authentication failed!");
});
}
console.log('i am returning');
return tokenObsr.asObservable();
}
更新:在深入研究您的代码后,我进行了必要的更改。 BehavoiurSubject
到 Subject
。尝试使用一次。
如果我正确理解了你想要实现的目标,我认为你应该重新组织你的代码以便能够利用 RxJs 的 Obsersable 模式。
这是我的建议
refreshToken(): Observable<string> {
const token_refreshed = localStorage.getItem("refresh_token");
let new_token: string;
if (token_refreshed) {
console.log("this refreshed token" + token_refreshed);
const headers = new HttpHeaders({
'Authorization': "Basic " + btoa("clientId:client-secret"),
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'refresh_token',
'refresh_token': token_refreshed
});
var creds = "grant_type=refresh_token" + "&credentials=true" + "&refresh_token=" + token_refreshed;
return this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers })
// Do not subscribe here - rather chain operators to transform the Observable returned by http.post into what you really want to emit and return the Observable transformed
.map(response => response.access_token)
.do(token => localStorage.setItem('access_token', response.token))
.do(token => console.log('I am returning', token)
}
如果你这样做,那么使用 refreshToken()
方法的任何人都必须订阅返回的 Observable 并在那里管理结果,例如
this.tokenService.refreshToken()
.subscribe(
token => {// do something with the token, maybe move here the localStore.setItem logic},
err => {// handle the error condition}
)
如果您必须等待令牌的 return,为什么不使用 Promise 而不是 Observable?
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers }).toPromise().then((t: UserToken) => {
localStorage.setItem('access_token', t.access_token);
new_token = t.access_token;
}).catch(() => {
console.log("User authentication failed!");
});
如果您想订阅其他地方的更改,请使用主题。
// in your constructor
this.sub = new Subject();
// in your method to get the token
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers }).toPromise().then((t: UserToken) => {
localStorage.setItem('access_token', t.access_token);
new_token = t.access_token;
this.sub.next(new_token);
}).catch(() => {
console.log("User authentication failed!");
});
// getter for the subject
// use asObservable so other components can't use next(..) to push data
get tokenSub(): Observable<String> {
return this.sub.asObservable();
}
// somewhere else
this.yourServer.tokenSub.subscribe((token: String) => {
....
}
我想将 observable 延迟到 return 值,直到我从订阅中的 HTTP 请求中得到 new_token。我也在用延迟时间,但我无法成功。
Error: returning undefined value
Expected: new_token returned from server
refreshToken(): Observable<string> {
const token_refreshed = localStorage.getItem("refresh_token");
let new_token: string;
if (token_refreshed) {
console.log("this refreshed token" + token_refreshed);
const headers = new HttpHeaders({
'Authorization': "Basic " + btoa("clientId:client-secret"),
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'refresh_token',
'refresh_token': token_refreshed
});
var creds = "grant_type=refresh_token" + "&credentials=true" + "&refresh_token=" + token_refreshed;
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers })
.subscribe(response => {
localStorage.setItem('access_token', response.access_token);
new_token = response.access_token;
}, err => {
console.log("User authentication failed!");
});
}
console.log('i am returning');
return Observable.of(new_token).delay(3000);
}
更新:正在消耗的方法refresh_token,我正在使用拦截器,401 方法在下面
handle401Error(req: HttpRequest<any>, next: HttpHandler) {
if (!this.isRefreshingToken) {
this.isRefreshingToken = true;
console.log('I am handler 401');
// Reset here so that the following requests wait until the token
// comes back from the refreshToken call.
this.tokenSubject.next(null);
return this.authService.refreshToken()
.switchMap((newToken: string) => {
console.log('map token' + newToken);
//I'm getting null new token here from authService.refreshToken()
if (newToken) {
this.tokenSubject.next(newToken);
return next.handle(this.addToken(req, newToken));
}
return this.logoutUser();
})
.catch(error => {
console.log('bad news its catch');
return this.logoutUser();
})
.finally(() => {
this.isRefreshingToken = false;
});
} else {
return this.tokenSubject
.filter(token => token != null)
.take(1)
.switchMap(token => {
console.log('i am switch map else ');
return next.handle(this.addToken(req, token));
});
}
}
不要订阅 post
请求,如果您想执行某些 side-effects 请求,请改用 do
运算符。
if (token_refreshed) {
return this.httplclient.post(...)
.do(response => {
localStorage...
})
.map(response => ...) // map the response to return only the new token?
.delay(3000); // or maybe you don't need this?
}
return Observable.of(new_token).delay(3000);
你不需要延迟。只要值可用就传递它,因为您无法确定该值在 3000 毫秒后是否可用。
refreshToken(): Observable<string> {
const tokenObsr = new Subject<string>();
const token_refreshed = localStorage.getItem("refresh_token");
if (token_refreshed) {
console.log("this refreshed token" + token_refreshed);
const headers = new HttpHeaders({
'Authorization': "Basic " + btoa("clientId:client-secret"),
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'refresh_token',
'refresh_token': token_refreshed
});
var creds = "grant_type=refresh_token" + "&credentials=true" + "&refresh_token=" + token_refreshed;
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers })
.subscribe(response => {
localStorage.setItem('access_token', response.access_token);
tokenObsr.next(response.access_token);
}, err => {
console.log("User authentication failed!");
});
}
console.log('i am returning');
return tokenObsr.asObservable();
}
更新:在深入研究您的代码后,我进行了必要的更改。 BehavoiurSubject
到 Subject
。尝试使用一次。
如果我正确理解了你想要实现的目标,我认为你应该重新组织你的代码以便能够利用 RxJs 的 Obsersable 模式。
这是我的建议
refreshToken(): Observable<string> {
const token_refreshed = localStorage.getItem("refresh_token");
let new_token: string;
if (token_refreshed) {
console.log("this refreshed token" + token_refreshed);
const headers = new HttpHeaders({
'Authorization': "Basic " + btoa("clientId:client-secret"),
'Content-Type': 'application/x-www-form-urlencoded',
'grant_type': 'refresh_token',
'refresh_token': token_refreshed
});
var creds = "grant_type=refresh_token" + "&credentials=true" + "&refresh_token=" + token_refreshed;
return this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers })
// Do not subscribe here - rather chain operators to transform the Observable returned by http.post into what you really want to emit and return the Observable transformed
.map(response => response.access_token)
.do(token => localStorage.setItem('access_token', response.token))
.do(token => console.log('I am returning', token)
}
如果你这样做,那么使用 refreshToken()
方法的任何人都必须订阅返回的 Observable 并在那里管理结果,例如
this.tokenService.refreshToken()
.subscribe(
token => {// do something with the token, maybe move here the localStore.setItem logic},
err => {// handle the error condition}
)
如果您必须等待令牌的 return,为什么不使用 Promise 而不是 Observable?
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers }).toPromise().then((t: UserToken) => {
localStorage.setItem('access_token', t.access_token);
new_token = t.access_token;
}).catch(() => {
console.log("User authentication failed!");
});
如果您想订阅其他地方的更改,请使用主题。
// in your constructor
this.sub = new Subject();
// in your method to get the token
this.httplclient.post<UserToken>('/api/oauth/token', creds, { headers: headers }).toPromise().then((t: UserToken) => {
localStorage.setItem('access_token', t.access_token);
new_token = t.access_token;
this.sub.next(new_token);
}).catch(() => {
console.log("User authentication failed!");
});
// getter for the subject
// use asObservable so other components can't use next(..) to push data
get tokenSub(): Observable<String> {
return this.sub.asObservable();
}
// somewhere else
this.yourServer.tokenSub.subscribe((token: String) => {
....
}