如何 运行 http 将请求置于循环中并获取每个单独请求的状态

How to run http put request in a loop and get status of every individual request

我有一个对象数组,它的每个对象都需要通过 put http 请求在数据库中更新。

[
{id: "3e81731f-e3b4-405d-a5ca-bef52c1b036a", date_created: "2019-07-24T15:55:31.372460Z", date_modified: "2020-07-13T03:25:02.720870Z", einsight_uuid: "d15176ab-ecf8-dba1-e040-10ac316407fa", attributes: {…}},
{id: "4707bff2-8265-456f-a4d4-ca1134d85620", date_created: "2019-07-24T15:55:31.372460Z", date_modified: "2020-07-13T03:25:06.238019Z", einsight_uuid: "fcda4259-3ecb-4566-85b0-5b6d5c7647f6", attributes: {…}}
{id: "d29a3340-04b6-431b-8671-a0f0d25a9b51", date_created: "2019-07-24T15:55:31.3724", date_modified: "2020-07-13T03:25:06.238019Z", einsight_uuid: "fcda4259-3ecb-4566-85b0-5b6d5c7647f6", attributes: {…}}
]

如何调用 api 将每条记录保存在数组中。在循环中调用 Api 是一个简单的选择,但还不够。我想记录每个回复。他们中有多少人成功或失败了。 在 angular 或 rxjs

中是否有任何可用的已知最佳实践来执行此类操作

您可以使用 rxjs concat,但 concat 会在 observable 抛出错误时停止,因此您可以使用 catchError return 一个新的 observable

import { of ,concat} from 'rxjs';
....
 data = [
    {id:1},
    {id:2},
    {id:-1},
    {id:2},

    ]
  constructor(private http:HttpClient){
    let httpReqs = this.data
          .map(i => 
              this.http.put(`https://jsonplaceholder.typicode.com/posts/${i.id}`,{})
              .pipe(catchError(err => of({err})))
              );

     concat(...httpReqs).subscribe(console.log)
    }

demo

检查这个rxjs concat

您可以根据请求的数量和您的要求并行或顺序请求。

并行请求

使用 RxJS forkJoin function with tap and catchError 运算符。尝试以下

import { forkJoin, of, from } from 'rxjs';
import { tap, catchError, concatMap } from 'rxjs/operators';

putDataParallel() {
  let success = 0;                   // <-- trivial counters
  let errors = 0;

  const reqs = this.urls.map(url =>  // <-- replate `this.urls` with your object array
    this.http.put(url).pipe(         // <-- replace `url` with your own PUT request
      tap(_ => success++),           // <-- count successful responses here
      catchError(err => {        
        errors++;                    // <-- count errors here
        return of(err);              // <-- remember to return an observable from `catchError`
      })
    )
  );

  forkJoin(reqs).subscribe(
    null,                            // <-- you could change response callback to your requirement
    err => console.log(err),
    () => console.log(`Success: ${success}\nErrors: ${errors}`),
  );
}

顺序请求

对顺序数据流使用 RxJS from function and concatMap 运算符。尝试以下

import { forkJoin, of, from } from 'rxjs';
import { tap, catchError, concatMap } from 'rxjs/operators';

putDataSequential() {
  let success = 0;                      // <-- trivial counters
  let errors = 0;

  from(this.urls).pipe(                 // <-- replate `this.urls` with your object array
    concatMap(url => {
      return this.http.put(url).pipe(   // <-- replace `url` with your own PUT request
        tap(_ => success++),            // <-- count successful responses here
        catchError(err => {        
          errors++;                     // <-- count errors here
          return of(err);               // <-- remember to return an observable from `catchError`
        })
      )
    })
  ).subscribe(
    null,                               // <-- you could change response callback to your requirement
    err => console.log(err),
    () => console.log(`Success: ${success}\nErrors: ${errors}`),
  );
}

无论错误或响应如何,这两种方法都将 运行 直到数组中的所有对象都完成。但是,如果您希望在出现错误时中断序列,请替换 catchError 运算符中的 return of(err); 语句以抛出 errorcomplete 通知。例如你可以使用 RxJS EMPTY 常量:return EMPTY;.

我以普通计数器为例。您可以改为使用对象(例如)来记录 response/errors 的数量和 HTTP 请求的相应输入。

工作示例:Stackblitz

如您所见,每个项目都将使用 concateMap 进行处理,并且在发出 HTTP 请求后,每个项目 result 数组都会更新。 有多种方法,你可以达到这个结果。这是此处显示的方法之一。

 items =[
       {id: "3e81731f-e3b4-405d-a5ca-bef52c1b036a", name :'united', result:[]},
       {id: "4707bff2-8265-456f-a4d4-ca1134d85620", name: 'ind', result:[]},
       {id: "d29a3340-04b6-431b-8671-a0f0d25a9b51", name:'ru', result:[]},
       {id: "xxx-xxxx-xxxx-xxxxx", name:'', result:[]}
    ]



from(this.items)
    .pipe(
        concatMap(item => this.ob2(item.name).pipe(
          catchError(err=>of(err)),
          tap(result =>{
            if(result.length){
              item.result = result;
            }else{
              // error scenario can be handled here
            }
            console.log('Updated each item', item)
          })
        ))
    ).subscribe();
  }

DEMO