Angular HttpClient请求未执行问题排查求助
Angular HttpClient请求无法触发排查
问题描述
无法触发HttpClient请求,推测是导入或配置问题,但找不到原因。API本身可用,但从未被调用。
环境版本
- Angular: 15.1.2
- CLI: 15.1.3
- Node: 16.14.2
- Package Manager: npm 8.5.0
- OS: win32 x64
项目结构
主着陆页包含多个widgets(快速查看内容的组件),每个widget对应独立组件。为widget提供数据的Service使用providedIn: 'root',并暴露Observable供组件订阅。
相关代码
app.module.ts
const pipes = [ SignUpFormTextPipe, StageFormatTextPipe, StageTypeTextPipe, TeamSizeTextPipe, TournamentStatusTextPipe, ]; const providers = [HttpClientModule]; @NgModule({ declarations: [...components, ...pipes], imports: [ BrowserModule, FormsModule, ReactiveFormsModule, AppRoutingModule, HttpClientModule, ], providers: [...pipes, ...providers], bootstrap: [AppComponent], })
TournamentService
import { HttpClient } from '@angular/common/http'; import { Injectable } from '@angular/core'; import { Tournament } from '../models/tournament/tournament'; import { BehaviorSubject, Observable, take, tap } from 'rxjs'; import { TournamentsResponse } from '../models/api-responses/tournament/tournaments-response'; @Injectable({ providedIn: 'root', }) export class TournamentService { private baseUrl: 'http://localhost:5077/api/tournamens'; initialTournaments: Tournament[] = []; private tournaments = new BehaviorSubject<Tournament[]>( this.initialTournaments ); public tournaments$ = this.tournaments.asObservable(); constructor(private httpClient: HttpClient) {} public getTournaments(): Observable<TournamentsResponse> { console.log('test 123'); // 此日志正常输出 return this.httpClient.get<TournamentsResponse>(this.baseUrl).pipe( tap((resp) => { console.log(resp); // 此日志未输出 this.tournaments.next(resp.tournaments); return resp; }), take(1) ); } }
订阅组件UpcomingTourneysComponent
import { Component, OnInit } from '@angular/core'; import { Observable, Subject, takeUntil } from 'rxjs'; import { Tournament } from 'src/app/models/tournament/tournament'; import { NotificationService } from 'src/app/services/common/notification.service'; import { TournamentService } from 'src/app/services/tournament.service'; @Component({ selector: 'app-upcoming-tourneys', templateUrl: './upcoming-tourneys.component.html', styleUrls: ['./upcoming-tourneys.component.css'], }) export class UpcomingTourneysComponent implements OnInit { private destroy$: Subject<void> = new Subject<void>(); upcomingTournaments$: Observable<Tournament[]> = this.tournamentService.tournaments$; constructor( private tournamentService: TournamentService, private notificationService: NotificationService ) {} ngOnInit() { console.log(this.tournamentService); // 此日志正常输出 this.tournamentService .getTournaments() .pipe(takeUntil(this.destroy$)) .subscribe({ next: (resp) => { console.log(resp); // 此日志未输出 }, error: (resp) => { this.notificationService.showError(resp); }, }); } }
组件HTML
test if component is rendered <div class="container-fluid" *ngIf="upcomingTournaments$ | async as upcomingTournaments"> <div class="card"> <div class="card-header" routerLink="/tournaments"> Upcoming tournaments </div> <div class="card-body"> <div *ngFor="let tourney of upcomingTournaments"> ... content... </div> </div> </div> </div>
我在另一个项目中使用相同模式可以正常工作,初步怀疑是导入错误,但IDE智能提示和代码检查工具未给出任何提示。
更新1:改用lastValueFrom仍无效
按照建议改用lastValueFrom(...),但HTTP请求仍未触发:
修改后的Service
@Injectable({ providedIn: 'root' }) export class TournamentService { private baseUrl: 'http://localhost:5077/api/tournamens'; initialTournaments: Tournament[] = []; private tournamentsSubject = new BehaviorSubject<Tournament[]>( this.initialTournaments ); public tournaments$ = this.tournamentsSubject.asObservable(); constructor(private httpClient: HttpClient) {} public getTournaments() { const result = lastValueFrom( this.httpClient.get<TournamentsResponse>(this.baseUrl) ).then((resp) => { this.tournamentsSubject.next(resp.tournaments); }); } }
修改后的组件TS
export class UpcomingTourneysComponent implements OnInit { upcomingTournaments$: Observable<Tournament[]> = this.tournamentService.tournaments$; constructor(private tournamentService: TournamentService) {} ngOnInit() { this.tournamentService.getTournaments(); } }
修改后的组件HTML
test if component is rendered {{ upcomingTournaments$ | async }} <div class="container-fluid" *ngIf="upcomingTournaments$ | async as upcomingTournaments" > .... </div>
更新2:简化调用仍报错
尝试移除所有Observable相关逻辑,简化调用,但仍未触发GET请求,且出现错误:
修改后的Service
public getTournaments(): Observable<TournamentsResponse> { return this.httpClient.get<TournamentsResponse>(this.baseUrl); }
修改后的组件
ngOnInit() { const response = this.tournamentService.getTournaments().subscribe({ next: (resp) => { console.log({ what: 'next call within service subscribe', resp }); // 输出错误:TypeError: Cannot read properties of undefined (reading 'toLowerCase') }, }); console.log({ what: 'upcomingTourneysInit', response }); // 此处Response为SafeSubscriber }
解决方案
问题根源
baseUrl声明错误:代码中private baseUrl: 'http://localhost:5077/api/tournamens';使用了类型注解(冒号:)而非变量赋值,导致baseUrl实际为undefined。HttpClient处理undefined的URL时,内部会调用toLowerCase()方法,从而抛出TypeError,但RxJS错误未被直观捕获,导致看起来请求未触发。- URL拼写错误:
tournamens应为tournaments(少了一个t),即使修复赋值问题,这个错误也会导致API请求404。
修复步骤
- 修正
baseUrl的赋值方式,同时修正拼写:
// 原错误代码 private baseUrl: 'http://localhost:5077/api/tournamens'; // 修正后 private baseUrl = 'http://localhost:5077/api/tournaments';
- 原有Observable订阅逻辑无需修改,保持即可。
- 验证API地址可访问,确认端口和路径正确。
验证修复
修正后,HttpClient会拿到正确的URL,正常触发请求,tap操作符中的日志会正常输出,组件订阅也能收到返回数据。
内容的提问来源于stack exchange,提问作者Neophyte
相关产品推荐
相关产品推荐

