当用户在 Angular 11+ 中单击“重试”时如何调用相同的 API?

问题描述 投票:0回答:1

当 api 需要超过 30 秒才能给出响应时,我想停止加载程序并简单地在页面上显示“重试”按钮。

当用户单击该按钮时,我想调用相同的 API。

我想在我的整个项目中实现整个过程,所以我希望它具有通用功能和 UI。

任何人都可以帮助我在全球范围内实现这一目标吗?因为我不想在每一页中编写相同的逻辑。

如果可能的话,我想编辑我的拦截器,这样如果 API 在 30 秒内没有响应,那么它会在组件/页面中显示“重试”按钮。现在,当按下组件的“重试”按钮时,会再次调用相同的 API。

注意:只有按下按钮才能再次调用 API,因此我们不能使用 rxjs 的重试方法。

让我知道是否有任何其他 rxjs 元素可以帮助实现这一目标

angular api rxjs
1个回答
0
投票

我试图通过服务和拦截器来实现你想要的。 主要思想是让您的根应用程序组件监视服务上引发超时的

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);
  }
}

希望这有帮助,如果有任何不清楚或错误的地方,请告诉我。

© www.soinside.com 2019 - 2024. All rights reserved.