为了账号安全,请及时绑定邮箱和手机立即绑定

Angular 中多个 HTTP 请求的最佳方式

Angular 中多个 HTTP 请求的最佳方式

德玛西亚99 2023-08-05 11:01:17
我正在尝试一一发送 2 个 HTTP 请求;如果第一个请求成功,则发送第二个请求,如果没有成功,则显示与第一个请求相应的错误消息。我计划使用类似的东西,但不确定它是否是这种情况的最佳选择:import { Component } from '@angular/core';import { HttpClient } from '@angular/common/http';@Component({  selector: 'app-root',  templateUrl: 'app/app.component.html'})export class AppComponent {  loadedCharacter: {};  constructor(private http: HttpClient) {}  ngOnInit() {    this.http.get('/api/people/1').subscribe(character => {      this.http.get(character.homeworld).subscribe(homeworld => {        character.homeworld = homeworld;        this.loadedCharacter = character;      });    });  }}我有不同的请求,例如 PUT 和 CREATE 也使用这种方法。我知道还有其他方法,例如forkjoin,,mergemap但如果这个方法解决了我的问题似乎更具可读性。任何想法?
查看完整描述

4 回答

?
料青山看我应如是

TA贡献1772条经验 获得超8个赞

首先,你的代码可以工作,这很好——你可以保持原样,一切都会好起来的。

另一方面,有一种多重改进的方法将在未来帮助您和您的同事:

  1. 尝试将与 http 相关的逻辑移至服务中,而不是在组件中调用 http - 这将帮助您将代码拆分为与视图相关的逻辑和与业务/获取/转换相关的逻辑。

  2. 尽量避免嵌套subscribes - 您不仅会忽略Observables 的强大功能,而且还会将代码绑定到某个流程,而无法在应用程序中的某个地方重用这些行。返回Observable可能会帮助您“共享”请求的结果或以某种方式对其进行转换。

  3. flatMap/mergeMapconcatMapswitchMap以不同的方式工作,使您能够按照自己想要的方式控制行为。不过,由于http.get()它们的工作原理几乎相似,因此最好尽快开始学习那些组合运算符。

  4. 考虑一下在这种情况下您将如何处理错误 - 如果您的第一次调用将导致错误,会发生什么?Observable有一个强大的机制来处理它们,同时.subscribe允许您仅以一种方式处理错误。

使用的示例switchMap

import { Component } from '@angular/core';

import { HttpClient } from '@angular/common/http';


@Component({

  selector: 'app-root',

  templateUrl: 'app/app.component.html'

})

export class AppComponent {

  loadedCharacter: {};

  constructor(private http: HttpClient) {}


  ngOnInit() {

    const character$ = this.http.get('/api/people/1').pipe(

      tap(character => this.characterWithoutHomeworld = character), // setting some "in-between" variable

      switchMap(character => {

        return this.http.get(character.homeworld).pipe(

            map(homeworld => {

                    return {

                        ...character,

                        homeworld: homeworld

                    }

                }

            )

        )

      }),

      catchError(errorForFirstOrSecondCall => {

        console.error('An error occurred: ', errorForFirstOrSecondCall);

        // if you want to handle this error and return some empty data use:

        // return of({});

        

        // otherwise: 

        throw new Error('Error: ' + errorForFirstOrSecondCall.message);

      })

);


    // you can either store this variable as `this.character$` or immediately subscribe to it like:

    character$.subscribe(loadedCharacter => {

        this.loadedCharacter = loadedCharacter;

    }, errorForFirstOrSecondCall => {

       console.error('An error occurred: ', errorForFirstOrSecondCall);

    })

  }

}


查看完整回答
反对 回复 2023-08-05
?
蝴蝶不菲

TA贡献1810条经验 获得超4个赞

2 嵌套订阅永远不是一个可行的方法。我推荐这种方法:


this.http.get('/api/people/1').pipe(

  switchMap(character => this.http.get(character.homeworld).pipe(

    map(homeworld => ({ ...character, homeworld })),

  )),

).subscribe(character => this.loadedCharacter = character);

编辑:对于你的大学


this.http.get('/api/people/1').pipe(

  switchMap(character => this.http.get(character.university).pipe(

    map(university => ({ ...character, university})),

  )),

).subscribe(character => this.loadedCharacter = character);

甚至连锁大学和家乡的请求


this.http.get('/api/people/1').pipe(

  switchMap(character => this.http.get(character.homeworld).pipe(

    map(homeworld => ({ ...character, homeworld })),

    // catchError(err => of({ ...character, homeworld: dummyHomeworld })),

  )),

  switchMap(character => this.http.get(character.university).pipe(

    map(university => ({ ...character, university})),

  )),

).subscribe(character => this.loadedCharacter = character);


查看完整回答
反对 回复 2023-08-05
?
素胚勾勒不出你

TA贡献1827条经验 获得超9个赞

switchmap您可以尝试使用和来更轻松地进行链接和错误处理的解决方案forkJoin。这将有助于保持代码干净,以防链不断增长成深嵌套。


    this.http

      .get("/api/people/1'")

      .pipe(

        catchError((err) => {

          // handle error

        }),

        switchMap((character) => {

          return forkJoin({

            character: of(character),

            homeworld: this.http.get(character.homeworld)

          });

        })

      )

      .subscribe(({ character, homeworld }) => {

        character.homeworld = homeworld;

        this.loadedCharacter = character;

      });

编辑:场景 2


this.http

      .get("/api/people/1")

      .pipe(

        catchError((err) => {

          console.log("e1", err);

        }),

        switchMap((character) => {

          return forkJoin({

            character: of(character),

            homeworld: this.http.get(character.homeworld).pipe(

              catchError((err) => {

                console.log("e2", err);

              })

            )

          });

        })

      )

      .subscribe(({ character, homeworld }) => {

        character.homeworld = homeworld;

        this.loadedCharacter = character;

      });

您可以链接捕获错误或添加单独的错误处理函数,而无需调用下一个 API 调用。但我建议将后端逻辑抽象为角度服务并使用此方法。这将有助于保持易于阅读的结构。


查看完整回答
反对 回复 2023-08-05
?
慕田峪4524236

TA贡献1875条经验 获得超5个赞

您可以通过检查状态码来检查第一次请求是否成功:


  ngOnInit() {

    this.http.get('/api/people/1').subscribe((character: HttpResponse<any>) => {

      // here you should look for the correct status code to check, in this example it's 200

      if (character.status === 200) {

        this.http.get(character.homeworld).subscribe(homeworld => {

          character.homeworld = homeworld;

          this.loadedCharacter = character;

        });

      } else {

        // character is gonna contain the error

        console.log(character)

      }

    });

  }


查看完整回答
反对 回复 2023-08-05
  • 4 回答
  • 0 关注
  • 157 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信