我正在尝试实施一个利用Spotify的安全api的Spotify搜索应用。
我需要找出一种异步执行此操作的方法,而不必在每次调用时都重新进行身份验证。 Spotify的令牌有效期为一个小时,因此我几乎不需要刷新。
目标:
我希望它遵循以下逻辑流程:
1)检查存储的令牌 2)如果令牌丢失或过期,请检索新令牌并存储 3)将存储的令牌返回搜索功能
问题:
当前,应用将在检索新令牌之前执行调用。我确实设法一次将它包装在一个Promise中,但是搜索调用最初只执行一次,然后什么也没有执行。
我正在寻找有关如何处理异步if / else逻辑的建议。
我已经阅读了有关新的HttpInterceptor的信息,但它们似乎更适合于用户具有单独登录名的应用程序。此应用将使用客户端凭据。
我愿意接受任何对此有任何建议的建议!
以下是我的代码的一些相关示例:
import {Injectable, OnInit} from '@angular/core';
import { HttpClient, HttpHeaders} from '@angular/common/http';
import { map, mergeMap } from 'rxjs/operators';
import { Observable, Timestamp} from '../../../node_modules/rxjs';
import {Auth} from '../../../Auth';
import { of } from 'rxjs';
import { from } from 'rxjs';
@Injectable()
export class SpotifyService {
private searchUrl: string;
private artistUrl: string;
private albumsUrl: string;
private albumUrl: string;
private authUrl: string;
private authTime: number;
constructor(private _http: HttpClient,
private auth: Auth) {
this.getAuth().subscribe();
}
searchMusic(str: string, type = 'artist') {
return this.getAuth().pipe(mergeMap(res => {
const headers = new HttpHeaders().set('Authorization', 'Bearer ' + this.auth.access_token);
this.searchUrl = 'https://api.spotify.com/v1/search?query=' + str + '&offset=0&limit=20&type=' + type + '&market=US';
return this._http.get(this.searchUrl, {headers: headers }).pipe(map(resp => {
console.log(resp);
return resp;
}));
}));
}
getAccessToken() {
this.authUrl = 'https://spot-auth.herokuapp.com/api/authorize';
return this._http.get(this.authUrl);
}
getAuth() {
const simpleObservable = new Observable((observer) => {
// observable execution
if (this.auth.access_token == null || this.authTime < (new
Date().getSeconds() - 60)) {
observer.next(this.getAccessToken().pipe(map(res => {
this.authTime = new Date();
this.auth = res;
})));
}
observer.complete();
});
return simpleObservable;
}
}
import { Component } from '@angular/core';
import {SpotifyService} from '../../services/spotify.service';
import {Artist} from '../../../../Artist';
@Component({
moduleId: module.id,
selector: 'search',
templateUrl: 'search.component.html'
})
export class SearchComponent {
searchStr: string;
searchRes: Artist[];
constructor(private _spotifyService: SpotifyService) {
}
searchMusic() {
this._spotifyService.searchMusic(this.searchStr).subscribe(res => {
this.searchRes = res.artists.items;
});
}
}
<h1>Need Music?</h1>
<p class="lead">Use the ngSpotify app to browse new releases and find your favorite songs<br> All you get is this text and a mostly barebones HTML document.</p>
<form>
<div class="form-group">
<input class="form-control" type="text" placeholder="Search Artists..." [(ngModel)]="searchStr" name="searchStr" (keyup)="searchMusic()">
</div>
</form>
<div *ngIf="searchRes">
<div *ngFor="let artist of searchRes">
<div class="row">
<div class="col-md-12">
<div class="search-res well">
<h4><a routerLink="/artist/{{artist.id}}">{{artist.name}}</a></h4>
<div>
<strong>Genres: </strong>
<span *ngFor="let genre of artist.genres">{{genre}}</span>
</div>
</div>
</div>
</div>
</div>
</div>