当 api 需要超过 30 秒才能给出响应时,我想停止加载程序并简单地在页面上显示“重试”按钮。
当用户单击该按钮时,我想调用相同的 API。
我想在我的整个项目中实现整个过程,所以我希望它具有通用功能和 UI。
任何人都可以帮助我在全球范围内实现这一目标吗?因为我不想在每一页中编写相同的逻辑。
如果可能的话,我想编辑我的拦截器,这样如果 API 在 30 秒内没有响应,那么它会在组件/页面中显示“重试”按钮。现在,当按下组件的“重试”按钮时,会再次调用相同的 API。
注意:只有按下按钮才能再次调用 API,因此我们不能使用 rxjs 的重试方法。
让我知道是否有任何其他 rxjs 元素可以帮助实现这一目标
我试图通过服务和拦截器来实现你想要的。 主要思想是让您的根应用程序组件监视服务上引发超时的
err
变量。我正在使用 html 对话框,以便错误呈现在其他组件上方。
完整 Stackblitz:https://stackblitz.com/edit/stackblitz-starters-c12rhx?file=src%2Fmain.ts
app.component
:
import { Component, OnInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { DelayedService } from './delayed.service';
import {
HTTP_INTERCEPTORS,
provideHttpClient,
withInterceptorsFromDi,
} from '@angular/common/http';
import { GlobalHttpInterceptorService } from './global-http.interceptor';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
template: `
<h1>value: {{ res }}</h1>
// Dialog opens when the service has error'd
<dialog [open]="!!delayedService.err">
<p>Conntection timed out</p>
<form method="dialog">
<button (click)="retry()">Retry</button>
</form>
</dialog>
`,
})
export class App implements OnInit {
name = 'Angular';
constructor(public delayedService: DelayedService) {}
res: any;
import { Component, OnInit } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { DelayedService } from './delayed.service';
import {
HTTP_INTERCEPTORS,
provideHttpClient,
withInterceptorsFromDi,
} from '@angular/common/http';
import { GlobalHttpInterceptorService } from './global-http.interceptor';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-root',
standalone: true,
imports: [CommonModule],
template: `
<h1>value: {{ res }}</h1>
<dialog [open]="!!delayedService.err">
<p>Conntection timed out</p>
<form method="dialog">
<button (click)="retry()">Retry</button>
</form>
</dialog>
`,
})
export class App implements OnInit {
name = 'Angular';
constructor(public delayedService: DelayedService) {}
res: any;
ngOnInit() {
this.delayedService
.get('foo', 'https://httpstat.us/200?sleep=5000')
.subscribe((res) => (this.res = res));
}
retry() {
this.delayedService.retryLastRequest();
}
}
bootstrapApplication(App, {
providers: [
provideHttpClient(withInterceptorsFromDi()),
{
provide: HTTP_INTERCEPTORS,
useClass: GlobalHttpInterceptorService,
multi: true,
},
],
});
// subscribe to service, you can do this in any component.
ngOnInit() {
this.delayedService
.get('foo', 'https://httpstat.us/200?sleep=5000')
.subscribe((res) => (this.res = res));
}
// retry the last request
retry() {
this.delayedService.retryLastRequest();
}
}
// if you are using without standalone, this must move to the provider section of the app module, let me know if you need me to rewrite for modules.
bootstrapApplication(App, {
providers: [
provideHttpClient(withInterceptorsFromDi()),
{
provide: HTTP_INTERCEPTORS,
useClass: GlobalHttpInterceptorService,
multi: true,
},
],
});
global-http.interceptor.ts
文件拦截并实现所需的超时。
import { Injectable } from '@angular/core';
import {
HttpEvent,
HttpHandler,
HttpInterceptor,
HttpRequest,
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { timeout } from 'rxjs/operators';
@Injectable({ providedIn: 'root' })
export class GlobalHttpInterceptorService implements HttpInterceptor {
intercept(
req: HttpRequest<any>,
next: HttpHandler
): Observable<HttpEvent<any>> {
return next.handle(req).pipe(timeout(3000));
}
}
进行 http 调用的服务确保在服务上设置
err
变量:
import { HttpClient } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, map, throwError } from 'rxjs';
@Injectable({
providedIn: 'root',
})
export class DelayedService {
lastRequestUrl: string = '';
lastRequestOptions: any;
err: any;
constructor(private http: HttpClient) {}
get(val: any, url: string) {
this.lastRequestUrl = url;
this.lastRequestOptions = {
responseType: 'text',
};
return this.http.get(this.lastRequestUrl, this.lastRequestOptions).pipe(
map(() => val),
catchError((err) => {
this.err = err;
return throwError(() => err);
})
);
}
retryLastRequest() {
console.log(this.lastRequestUrl);
}
}
希望这有帮助,如果有任何不清楚或错误的地方,请告诉我。