Я использую angular и rxjs, и делаю следующее:
Я хотел бы загрузить изображение в GCP, поэтому мне нужно создать подписанный URL-адрес, загрузить изображение и при этом показать статус всего запроса.
Компонент => попросите службу A загрузить файл.
this.uploadProgress$ = this.uploadHelperService.uploadImage(userId, image);
this.subscriptions.add(
this.uploadProgress$.subscribe((result) => {
if (result.status !== UploadStatus.SUCCESS) {
return;
}
// Everything worked
})
);
Сервис A => Просто привяжите вызов API, чтобы сгенерировать подписанный URL
uploadImage(userId: string, image: File) {
const urlGenerator = this.apiService
.generateUploadUrl({
userId,
filename: image.name,
})
.pipe(
map((result) => result.data?.url || ''),
catchError((e) => throwError(e))
);
return this.gcpUploaderService.uploadToGCP(urlGenerator, images[0]);
}
Сервис B => Сгенерируйте URL-адрес и загрузите файл, отслеживая прогресс.
uploadToGCP(
generator$: Observable<string>,
file: File
): Observable<{
url?: string;
status: UploadStatus;
}> {
return new Observable((subscriber) => {
subscriber.next({
status: UploadStatus.INIT,
});
generator$.pipe(
switchMap((url) => {
subscriber.next({
status: UploadStatus.UPLOADING,
});
return this.httpClient
.put(url, file, {
headers: new HttpHeaders({ 'Content-Type': file.type }),
})
.pipe(
map(() => {
subscriber.next({
url,
status: UploadStatus.SUCCESS,
});
subscriber.complete();
}),
catchError((e) => {
subscriber.next({
status: UploadStatus.FAILED,
});
subscriber.complete();
return throwError(e);
})
);
}),
catchError((e) => {
subscriber.next({
status: UploadStatus.FAILED,
});
subscriber.complete();
return throwError(e);
})
);
});
}
Теперь все это работает, но это дрянно, и я считаю, что можно значительно улучшить, особенно последнюю часть. Но мне сегодня не хватает вдохновения.