Ionic HTTP请求 #

一、HttpClient概述 #

1.1 导入HttpClientModule #

typescript
// app.module.ts
import { HttpClientModule } from '@angular/common/http';

@NgModule({
  imports: [
    HttpClientModule
  ]
})
export class AppModule {}

1.2 基本使用 #

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

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html'
})
export class HomePage {
  constructor(private http: HttpClient) {}
  
  getUsers() {
    this.http.get<any[]>('https://api.example.com/users').subscribe({
      next: (data) => console.log(data),
      error: (error) => console.error(error)
    });
  }
}

二、HTTP方法 #

2.1 GET请求 #

typescript
// 基本GET请求
getUsers() {
  return this.http.get<User[]>('/api/users');
}

// 带参数的GET请求
import { HttpParams } from '@angular/common/http';

searchUsers(keyword: string, page: number) {
  const params = new HttpParams()
    .set('keyword', keyword)
    .set('page', page.toString());
  
  return this.http.get<User[]>('/api/users', { params });
}

// 带选项的GET请求
getUser(id: string) {
  return this.http.get<User>(`/api/users/${id}`, {
    observe: 'response',
    responseType: 'json'
  });
}

2.2 POST请求 #

typescript
// 基本POST请求
createUser(user: User) {
  return this.http.post<User>('/api/users', user);
}

// 带选项的POST请求
login(credentials: LoginCredentials) {
  return this.http.post<AuthResponse>('/api/auth/login', credentials, {
    headers: new HttpHeaders({
      'Content-Type': 'application/json'
    })
  });
}

2.3 PUT请求 #

typescript
updateUser(id: string, user: User) {
  return this.http.put<User>(`/api/users/${id}`, user);
}

2.4 PATCH请求 #

typescript
partialUpdateUser(id: string, changes: Partial<User>) {
  return this.http.patch<User>(`/api/users/${id}`, changes);
}

2.5 DELETE请求 #

typescript
deleteUser(id: string) {
  return this.http.delete<void>(`/api/users/${id}`);
}

三、API服务封装 #

3.1 基础API服务 #

typescript
// services/api.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpParams, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  private baseUrl = 'https://api.example.com';
  
  constructor(private http: HttpClient) {}
  
  get<T>(endpoint: string, params?: any): Observable<T> {
    let httpParams = new HttpParams();
    
    if (params) {
      Object.keys(params).forEach(key => {
        httpParams = httpParams.set(key, params[key]);
      });
    }
    
    return this.http.get<T>(`${this.baseUrl}${endpoint}`, { params: httpParams });
  }
  
  post<T>(endpoint: string, data: any): Observable<T> {
    return this.http.post<T>(`${this.baseUrl}${endpoint}`, data);
  }
  
  put<T>(endpoint: string, data: any): Observable<T> {
    return this.http.put<T>(`${this.baseUrl}${endpoint}`, data);
  }
  
  patch<T>(endpoint: string, data: any): Observable<T> {
    return this.http.patch<T>(`${this.baseUrl}${endpoint}`, data);
  }
  
  delete<T>(endpoint: string): Observable<T> {
    return this.http.delete<T>(`${this.baseUrl}${endpoint}`);
  }
}

3.2 用户服务 #

typescript
// services/user.service.ts
import { Injectable } from '@angular/core';
import { ApiService } from './api.service';
import { Observable } from 'rxjs';

export interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
}

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private endpoint = '/users';
  
  constructor(private api: ApiService) {}
  
  getUsers(params?: { page?: number; limit?: number }): Observable<User[]> {
    return this.api.get<User[]>(this.endpoint, params);
  }
  
  getUser(id: string): Observable<User> {
    return this.api.get<User>(`${this.endpoint}/${id}`);
  }
  
  createUser(user: Partial<User>): Observable<User> {
    return this.api.post<User>(this.endpoint, user);
  }
  
  updateUser(id: string, user: Partial<User>): Observable<User> {
    return this.api.put<User>(`${this.endpoint}/${id}`, user);
  }
  
  deleteUser(id: string): Observable<void> {
    return this.api.delete<void>(`${this.endpoint}/${id}`);
  }
}

四、HTTP拦截器 #

4.1 认证拦截器 #

typescript
// interceptors/auth.interceptor.ts
import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor
} from '@angular/common/http';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor(private auth: AuthService) {}
  
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const token = this.auth.getToken();
    
    if (token) {
      request = request.clone({
        setHeaders: {
          Authorization: `Bearer ${token}`
        }
      });
    }
    
    return next.handle(request);
  }
}

4.2 日志拦截器 #

typescript
// interceptors/logging.interceptor.ts
import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpResponse,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, tap } from 'rxjs';

@Injectable()
export class LoggingInterceptor implements HttpInterceptor {
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    const startTime = Date.now();
    
    return next.handle(request).pipe(
      tap({
        next: (event) => {
          if (event instanceof HttpResponse) {
            const duration = Date.now() - startTime;
            console.log(`${request.method} ${request.url} - ${duration}ms`);
          }
        },
        error: (error: HttpErrorResponse) => {
          const duration = Date.now() - startTime;
          console.error(`${request.method} ${request.url} - ${duration}ms - Error: ${error.message}`);
        }
      })
    );
  }
}

4.3 错误处理拦截器 #

typescript
// interceptors/error.interceptor.ts
import { Injectable } from '@angular/core';
import {
  HttpRequest,
  HttpHandler,
  HttpEvent,
  HttpInterceptor,
  HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { catchError } from 'rxjs/operators';
import { Router } from '@angular/router';
import { ToastController } from '@ionic/angular';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(
    private router: Router,
    private toastCtrl: ToastController
  ) {}
  
  intercept(
    request: HttpRequest<any>,
    next: HttpHandler
  ): Observable<HttpEvent<any>> {
    return next.handle(request).pipe(
      catchError((error: HttpErrorResponse) => {
        let message = '发生未知错误';
        
        if (error.error instanceof ErrorEvent) {
          message = `客户端错误: ${error.error.message}`;
        } else {
          switch (error.status) {
            case 0:
              message = '网络连接失败';
              break;
            case 401:
              message = '未授权,请重新登录';
              this.router.navigate(['/auth/login']);
              break;
            case 403:
              message = '没有权限访问';
              break;
            case 404:
              message = '请求的资源不存在';
              break;
            case 500:
              message = '服务器内部错误';
              break;
            default:
              message = error.error?.message || `请求失败 (${error.status})`;
          }
        }
        
        this.showToast(message);
        return throwError(() => error);
      })
    );
  }
  
  private async showToast(message: string) {
    const toast = await this.toastCtrl.create({
      message,
      duration: 3000,
      color: 'danger',
      position: 'top'
    });
    await toast.present();
  }
}

4.4 注册拦截器 #

typescript
// app.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './interceptors/auth.interceptor';
import { LoggingInterceptor } from './interceptors/logging.interceptor';
import { ErrorInterceptor } from './interceptors/error.interceptor';

@NgModule({
  providers: [
    { provide: HTTP_INTERCEPTORS, useClass: AuthInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: LoggingInterceptor, multi: true },
    { provide: HTTP_INTERCEPTORS, useClass: ErrorInterceptor, multi: true }
  ]
})
export class AppModule {}

五、错误处理 #

5.1 服务层错误处理 #

typescript
// services/user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable, throwError, retry, catchError } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  constructor(private http: HttpClient) {}
  
  getUsers(): Observable<User[]> {
    return this.http.get<User[]>('/api/users').pipe(
      retry(2),
      catchError(this.handleError)
    );
  }
  
  private handleError(error: HttpErrorResponse) {
    let errorMessage = '';
    
    if (error.error instanceof ErrorEvent) {
      errorMessage = `Error: ${error.error.message}`;
    } else {
      errorMessage = `Error Code: ${error.status}\nMessage: ${error.message}`;
    }
    
    return throwError(() => new Error(errorMessage));
  }
}

5.2 组件层错误处理 #

typescript
import { Component } from '@angular/core';
import { UserService } from './user.service';
import { LoadingController, ToastController } from '@ionic/angular';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html'
})
export class HomePage {
  users: User[] = [];
  isLoading = false;
  
  constructor(
    private userService: UserService,
    private loadingCtrl: LoadingController,
    private toastCtrl: ToastController
  ) {}
  
  async loadUsers() {
    this.isLoading = true;
    
    const loading = await this.loadingCtrl.create({
      message: '加载中...'
    });
    await loading.present();
    
    this.userService.getUsers().subscribe({
      next: (users) => {
        this.users = users;
        this.isLoading = false;
        loading.dismiss();
      },
      error: (error) => {
        this.isLoading = false;
        loading.dismiss();
        this.showError(error.message);
      }
    });
  }
  
  private async showError(message: string) {
    const toast = await this.toastCtrl.create({
      message,
      duration: 3000,
      color: 'danger'
    });
    await toast.present();
  }
}

六、最佳实践 #

6.1 环境配置 #

typescript
// environments/environment.ts
export const environment = {
  production: false,
  apiUrl: 'http://localhost:3000/api'
};

// environments/environment.prod.ts
export const environment = {
  production: true,
  apiUrl: 'https://api.example.com'
};

// 服务中使用
import { environment } from 'src/environments/environment';

@Injectable({
  providedIn: 'root'
})
export class ApiService {
  private baseUrl = environment.apiUrl;
}

6.2 类型定义 #

typescript
// models/user.model.ts
export interface User {
  id: string;
  name: string;
  email: string;
  avatar?: string;
  createdAt?: Date;
  updatedAt?: Date;
}

export interface UserListResponse {
  data: User[];
  total: number;
  page: number;
  limit: number;
}

6.3 请求取消 #

typescript
import { Component } from '@angular/core';
import { UserService } from './user.service';
import { Subject, takeUntil } from 'rxjs';

@Component({
  selector: 'app-home',
  templateUrl: 'home.page.html'
})
export class HomePage implements OnDestroy {
  private destroy$ = new Subject<void>();
  
  constructor(private userService: UserService) {}
  
  loadUsers() {
    this.userService.getUsers()
      .pipe(takeUntil(this.destroy$))
      .subscribe(users => {
        this.users = users;
      });
  }
  
  ngOnDestroy() {
    this.destroy$.next();
    this.destroy$.complete();
  }
}

七、总结 #

7.1 HTTP要点 #

要点 说明
HttpClient Angular内置HTTP客户端
API服务 封装API调用逻辑
拦截器 请求/响应预处理
错误处理 统一错误处理机制
类型安全 使用TypeScript接口

7.2 下一步 #

掌握了HTTP请求后,接下来让我们学习 本地存储,了解Ionic的数据持久化!

最后更新:2026-03-28