TypeScript - איך אפשר לגשת למאפיין מתוך מתודת שירות ב-Angular?
אני חדש ב-Angular ואני מנסה להעביר טוקן מ-Spotify API לפונקציית שירות ב-Angular, אז יש לי נקודת קצה שמקבלת את הטוקן ועובדת, אבל כשאני קורא לפונקציה getQuery() אובייקט הפלט של 'headers' נראה משהו כמו:
{
Authorization: Bearer undefined
}
אז בגלל זה, כשאני רוצה לבצע בקשה, זה מחזיר סטטוס 401 כי אסימון הגישה שלי לא נכון.
ככה נראה השירות שלי ושיטת הבנאי:
import { Injectable } from '@angular/core';
import { HttpClient,HttpHeaders } from '@angular/common/http';
import { map } from 'rxjs/operators';
@Injectable({
providedIn: 'root'
})
export class SpotifyService {
private token:string
constructor(
private http:HttpClient,
) {
const clientId = 'my client id';
const clientSecret = 'my client secret';
this.getToken(clientId, clientSecret);
}
וזה מה שנראה הפונקציה getToken() שלי:
getToken(clientId:string, clientSecret:string){
const urlRequest = `https://myendpoint/${clientId}/${clientSecret}`;
this.http.get(urlRequest)
.subscribe( (data:any) =>{
this.token = data.access_token;
});
}
בנקודה זו הכל בסדר, אבל כשאני קורא לשירות זה מתוך קומפוננטה ואני קורא לשיטת שירות אחרת, נראה שהקונסטרקטור לא מתבצע כי אני מקבל את בעיית ה-undefined בשיטת השירות הזו:
getQuery( query:string ){
const url = `https://spotifyapi/${query}`;
const headers = new HttpHeaders({
'Authorization': `Bearer ${this.token}`
});
console.log(headers);
return this.http.get(url,{headers});
}
השתמשתי ב-console.log() כדי לבדוק אם אני מקבל את הטוקן ב-getToken() וזה עובד, אבל נראה שאני לא יכול לגשת אליו מהשיטה getQuery().
אני פשוט רוצה לעשות את הטוקן נגיש בשיטה הזאת כדי שאוכל לבצע בקשות.
תשובה #1
מכיוון ש-
this.http.getהיא קריאה אסינכרונית, עליך להמתין עד שהקריאה תסתיים. ניתן לעשות זאת כך בהתאם לאופן שבו אתה מממש זאת:
@Injectable({ providedIn: 'root' })
export class SpotifyService {
// Changing its type from a simple string to an Observable<string>
private token$: Observable<string>;
constructor(private http:HttpClient) {
const clientId = 'my client id';
const clientSecret = 'my client secret';
// Initialize the token
this.token = this.getToken(clientId, clientSecret);
}
getToken(clientId:string, clientSecret:string): Observable<any> {
const urlRequest = `https://myendpoint/${clientId}/${clientSecret}`;
// Call the token api and get only its "access_token"
return this.http.get(urlRequest).pipe(map(data => data.access_token));
}
getQuery( query:string ){
const url = `https://spotifyapi/${query}`;
// Subscribe to the token$ observable and assign the token on your headers
this.token$.subscribe(token => {
const headers = new HttpHeaders({ 'Authorization': `Bearer ${this.token}` });
console.log(headers);
return this.http.get(url, {headers});
});
}
}
דרך נוספת היא להשתמש ב-HTTP Interceptor
1.) לאחר שתתחבר, בדרך כלל זה ייתן לך את הטוקן. שמור את הטוקן הזה ב-localStorage שלך
localStorage.setItem('token:id', token);2.) צור auth.interceptor.ts
עם זה, בכל פעם שתתקשר ל-API שלך, זה יכניס אוטומטית את הכותרות שלך
@Injectable({ providedIn: 'root' })
export class AuthInterceptor implements HttpInterceptor {
intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
const token = localStorage.getItem('token:id');
if (token) {
const cloned = req.clone({ headers: req.headers.set('Authorization', `Bearer ${token}`) });
return next.handle(cloned);
}
else return next.handle(req);
}
}
3.) יבא את זה ל-AppModule או ל-CoreModule (אם יש לך)
@NgModule({
imports: [],
providers: [
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
})
export class AppModule {}
תשובה #2
נו, אני רואה כמה בעיות בדרך שבה אתה מנסה לפתור את הבעיה. כפי שהוצע בהערות, ייתכן שהאסימון לא נשלף לפני שבוצעה הקריאה. שקול לבצע את השינויים הבאים
- השתמש ב-APP_INITIALIZER כדי לטעון את הטוקן מראש, כך מובטח שיהיה לך את הטוקן לפני שהאפליקציה שלך מתחילה לטעון - תסתכל על - https://www.tektutorialshub.com/angular/angular-how-to-use-app-initializer/
- אם אסימון האימות נדרש בכל קריאה, לא כדאי להוסיף את הכותרת בכל שירות, שקול להוסיף חוצץ HTTP כדי להוסיף את כותרת האימות לפני כל שירות - https://medium.com/@ryanchenkie_40935/angular-authentication-using-the-http-client-and-http-interceptors-2f9d1540eb8
