【问题标题】:Avoid http request spam避免http请求垃圾邮件
【发布时间】:2021-06-14 14:21:29
【问题描述】:

我有一个拨动开关,当它被触发时会发出一个 http PATCH 请求。您可以在下面看到它的样子:

模板:

<div id="toggle-status-btn-container">
    <div class="slider" [ngClass]="{'to-right': !shopIsOpen}"></div>
    <div class="label-container">
        <label class="store-opened" (click)="updateShopSlotsStatus(true)" [ngClass]="{'toggled-opened-text': !shopIsOpen}">OPENED</label>
    </div>
    <div class="label-container">
        <label class="store-closed" (click)="updateShopSlotsStatus(false)" [ngClass]="{'toggled-closed-text': !shopIsOpen}">CLOSED</label>
    </div>
</div>

效果很好,但现在用户可以向这个切换开关发送垃圾邮件,连续触发多个 http 请求。

我能做些什么来防止这种行为?如果用户向此切换开关发送垃圾邮件,我不想触发 http 请求。也许有办法只触发最后一个?由于我对 RxJs 很陌生,我真的不知道如何解决这个问题。

这里是click事件调用的方法,在组件.ts中:

updateShopSlotsStatus(isOpen: boolean){
    this.shopIsOpen = isOpen;
    this.apiService.updateShopSlotsStatus(isOpen, this.weekDay).subscribe();
}

还有http请求,在一个服务文件中:

updateShopSlotsStatus(isOpen: boolean, weekDay: string){
    const endpoint = this.url + "shipping/" + this.webzineId + "/delivery_slots" + "/";
    return this.http.patch(endpoint, {"slots": { [weekDay] : { "enabled": isOpen }}});
}

提前致谢。

【问题讨论】:

  • 这能回答你的问题吗? Angular 2+ and debounce(您正在寻找的“东西”称为debouncing。此线程中有许多旧答案,但也有合适的最新答案。)
  • 感谢您的建议!我很难弄清楚如何调整其中一些答案来回答我的问题,因为其中许多都是关于表单控件和输入的。

标签: angular typescript rxjs


【解决方案1】:

您可能希望使用BehaviorSubjectswitchMap 的组合,例如this StackBlitz

在这里,我已将打开和关闭按钮绑定到一个更改 BehaviorSubjects 值的函数,如下所示:

模板:

  <button
    (click)="updateShopSlotsStatus(true)"
    [ngClass]="{'selected': shopSlotStatus$ | async}"
  >
    OPEN
  </button>
  <button
    (click)="updateShopSlotsStatus(false)"
    [ngClass]="{'selected': !(shopSlotStatus$ | async)}"
  >
    CLOSED
  </button>

ts:

  updateShopSlotsStatus(isOpen: boolean) {
    this.shopSlotStatusSubject$.next(isOpen);
  }

然后您可以像这样观察BehaviorSubject 上的变化:

  private shopSlotStatusSubject$: BehaviorSubject<
    boolean
  > = new BehaviorSubject(false);

  // shared so only one subscription is maintained
  private readonly shopSlotStatus$ = this.shopSlotStatusSubject$
    .asObservable()
    .pipe(share());

  readonly changeSlotStatus$ = this.shopSlotStatus$.pipe(
    // you could introduce a debounceTime here if you wanted
    // debounceTime(500),
    tap(() => (this.changingStatus = true)),
    // faked API call here
    switchMap(status => this.appService.updateShopSlotsStatus(status)),
    tap(() => (this.changingStatus = false))
  );

switchMap 运算符将在源(在本例中为 changeSlotStatus$ 可观察对象)发出时取消任何飞行中的可观察对象。

我在 Stackblitz 上包含了 exhaustMapmergeMap 的导入。将switchMap 更改为这两个运算符,以查看它们的工作方式有何不同。 exhaustMap 将忽略所有后续发射,直到正在进行的发射完成,mergeMap 将触发与按钮按下一样多的请求。我将由您决定哪种方法最好!您可以在learn rxjs. 了解更多信息,我建议您阅读 RxJS 和不同的运算符以及如何使用 pipe 编写它们。 RxJS 是个好东西。

如果您想在请求进行时禁用被按下的按钮,您还可以绑定到 changingStatus bool。

【讨论】:

  • 这正是我想要的。谢谢你的详细解答!
  • 不客气。起初,RxJS 对我来说非常令人生畏。坚持下去。
猜你喜欢
  • 2019-02-04
  • 2019-02-20
  • 1970-01-01
  • 2016-01-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多