服务器上取消了多个 API 调用

Posted

技术标签:

【中文标题】服务器上取消了多个 API 调用【英文标题】:multiple API calls canceled on server 【发布时间】:2019-12-15 18:49:33 【问题描述】:

我正在使用 Angular7 和 NGRX,以及 GO 中的服务器。

我的ngrx效果中有以下代码=>

  //#region OPEN CHANNELS
  @Effect()
  getUAVsSuccess$ = this.actions$.pipe(
    ofType<featureActions.GetUAVsSuccess>(featureActions.ActionTypes.GetUAVsSuccess),
    concatMap(action =>
      of(action).pipe(
        withLatestFrom(this.store$.pipe(select(featureSelectors.selectAll))),
        withLatestFrom(this.store$.pipe(select(OrganizationStoreSelectors.selectedOrganizationId))),
        withLatestFrom(this.store$.pipe(select(ProjectsStoreSelectors.selectedProjectId)))
      )
    ),
    switchMap(([[[action, drones], organizationId], projectId]) => 
      const actions = [];
      drones.forEach((drone) => 
        actions.push(
          new featureActions.OpenUAVUpdatePositionChannelRequest( uavId: drone.uavId, projectId, organizationId ),
          new featureActions.OpenUAVUpdateStatusChannelRequest( uavId: drone.uavId, projectId, organizationId ),
          new featureActions.GetUAVCurrentMissionRequest(uavId: drone.uavId)
        );
      );
      return actions;
    ),
  );

基本上这样会打开2个频道,然后得到一个任务。

最后一个动作,将派发另一个效果

  @Effect()
  getCurrentMission$ = this.actions$.pipe(
    ofType<featureActions.GetUAVCurrentMissionRequest>(featureActions.ActionTypes.GetUAVCurrentMissionRequest),
    switchMap((action) =>
      this.dataService.getCurrentMission(action.payload).pipe(
        switchMap(response => [
          new featureActions.GetUAVCurrentMissionSuccess(uavId : action.payload.uavId, missionHandler : response.identifier),
          new MissionsStoreActions.GetMissionUAVRequest(uavId : action.payload.uavId, missionHandler : response.identifier)
        ]),
        catchError((error: HttpErrorResponse) => 
          this.snackBar.open(this.translate.instant('ERROR.HTTP.DRONE.NOT_UPDATABLE', message: error.message), this.translate.instant('BUTTON.OK'), duration: 2500);
          return of(new featureActions.GetUAVCurrentMissionFailed(error));
        ),
      )
    )
  ); 

那个,使用 api 调用 getCurrentMission

会向服务器询问任务

  getCurrentMission(params: uavId: number): Observable<apiModels.GetMissionHandleResponse> 
    return this.httpClient.get<any>(`$environment.API_URL/mission/get_mission_handle_uav?uavID=$params.uavId`);
  

现在,我面临的问题是。如果我装载 4 架无人机,我总共将有 12 个呼叫。最后一次接听电话被取消了,因为它就像在短时间内被问了 3 次一样。

我不明白究竟是什么原因造成的。服务器确实得到调用检索数据(我在发送响应之前添加了日志),并发送响应,但是在浏览器上取消了调用,所以我的 ngrx init 调用流程中断了。当时只接听一个电话

可能是什么问题?

编辑:我还尝试在邮递员上运行一系列测试,无延迟地调用 5 次相同的端点,并且它有效。所以我猜ngrx或chrome中的某些东西正在取消我的电话?

【问题讨论】:

【参考方案1】:

你正在使用 switchMap 所以

switchMap 与其他扁平化操作符的主要区别 是消音效果。在每次发射上,前一个内部 observable(您提供的函数的结果)被取消并且 订阅了新的 observable(如果新的发射值快速发射 足够的)。

您可以通过短语 switch to a new 来记住这一点 可观察的

所以我建议你像这样更改代码

  @Effect()
  getCurrentMission$ = this.actions$.pipe(
    ofType<featureActions.GetUAVCurrentMissionRequest>(featureActions.ActionTypes.GetUAVCurrentMissionRequest),
    mergeMap((action) => // here
      this.dataService.getCurrentMission(action.payload).pipe(
        mergeMap(response => [ // here
          new featureActions.GetUAVCurrentMissionSuccess(uavId : action.payload.uavId, missionHandler : response.identifier),
          new MissionsStoreActions.GetMissionUAVRequest(uavId : action.payload.uavId, missionHandler : response.identifier)
        ]),
        catchError((error: HttpErrorResponse) => 
          this.snackBar.open(this.translate.instant('ERROR.HTTP.DRONE.NOT_UPDATABLE', message: error.message), this.translate.instant('BUTTON.OK'), duration: 2500);
          return of(new featureActions.GetUAVCurrentMissionFailed(error));
        ),
      )
    )
  );

或者使用exhaustMap

@Effect()
      getCurrentMission$ = this.actions$.pipe(
        ofType<featureActions.GetUAVCurrentMissionRequest>(featureActions.ActionTypes.GetUAVCurrentMissionRequest),
        exhaustMap((action) =>
          this.dataService.getCurrentMission(action.payload).pipe(
            tap(response =>  //change to map here
              new featureActions.GetUAVCurrentMissionSuccess(uavId : action.payload.uavId, missionHandler : response.identifier),
            ),
            tap(response =>
              new MissionsStoreActions.GetMissionUAVRequest(uavId : action.payload.uavId, missionHandler : response.identifier)
            ),
            catchError((error: HttpErrorResponse) => 
              this.snackBar.open(this.translate.instant('ERROR.HTTP.DRONE.NOT_UPDATABLE', message: error.message), this.translate.instant('BUTTON.OK'), duration: 2500);
              return of(new featureActions.GetUAVCurrentMissionFailed(error));
            ),
          )
        )
      ); 

【讨论】:

我已经尝试过 map,但问题是我得到了 ERROR Error: Effect "UAVsEffects.getCurrentMission$" dispatched an invalid action: ["payload":"uavId":3,"missionHandler":"2d","type":"[UAV] Get UAV Current Mission Success","payload":"uavId":3,"missionHandler":"2d","type":"[MISSION] Get Mission UAV Request"] 因为我无法使用简单的 map 调度一系列动作 我也试过mergeMap,但同样的结果有switchMap 或者你在水龙头里面使用this.store.dispatch。它也可以工作 我试过点击,它也取消了请求,但你给了我一个方向,谢谢你会继续调查 您可以在stackblitz.com 或github 上为我分享您的源代码吗?我很想看看

以上是关于服务器上取消了多个 API 调用的主要内容,如果未能解决你的问题,请参考以下文章

用户批准后如何取消Paypal订单? (API v2)

成功的预检,但取消了授权标题的回复

预检成功,但取消了带有授权标头的响应

Safari 在另一台服务器上调用 API 时拒绝 Cookie

多个 API 调用:设计模式

防止跨多个服务器重复 POST API 调用