Angular HTTP 客户端

Master Angular HTTP 客户端, implementation and after 端 API 交互

Angular HTTP 客户端overview

Angular HTTP 客户端 is Angular frameworkproviding 用于 and after 端 API for通信 module, 它基于浏览器 XMLHttpRequest API, 并providing了更强 big , 更易用 functions.

提示

Angular HTTP 客户端support发送 GET, POST, PUT, DELETE etc.各种 HTTP request, 并providing了拦截器, errorprocessing, requestconfigurationetc.advancedfunctions.

1. 启用 HTTP 客户端

要using Angular HTTP 客户端, 需要先import HttpClientModule:

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

@NgModule({
  imports: [
    BrowserModule,
    HttpClientModule // import HttpClientModule
  ],
  // ...
})
export class AppModule { }

2. basic HTTP request

Angular HTTP 客户端providing了 many 种method用于发送不同class型 HTTP request.

2.1 发送 GET request

// user.service.ts
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class UserService {
  private apiUrl = 'https://jsonplaceholder.typicode.com/users';

  constructor(private http: HttpClient) { }

  // 发送 GET request获取userlist
  getUsers(): Observable {
    return this.http.get(this.apiUrl);
  }

  // 发送 GET request获取单个user
  getUserById(id: number): Observable {
    return this.http.get(`${this.apiUrl}/${id}`);
  }
}

2.2 in componentinusing HTTP service

// user.component.ts
import { Component, OnInit } from '@angular/core';
import { UserService } from '../user.service';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.css']
})
export class UserComponent implements OnInit {
  users: any[] = [];
  loading = false;
  error = '';

  constructor(private userService: UserService) { }

  ngOnInit(): void {
    this.loading = true;
    // subscribe Observable 获取data
    this.userService.getUsers()
      .subscribe({
        next: (data) => {
          this.users = data;
          this.loading = false;
        },
        error: (err) => {
          this.error = err.message;
          this.loading = false;
        }
      });
  }
}

2.3 发送 POST request

POST request用于向serversubmittingdata, creation new resource:

// user.service.ts
export class UserService {
  // ...

  // 发送 POST requestcreationuser
  createUser(user: any): Observable {
    return this.http.post(this.apiUrl, user);
  }
}

// componentinusing
createUser() {
  const newUser = { name: '赵六', email: 'zhaoliu@example.com' };
  this.userService.createUser(newUser)
    .subscribe({
      next: (data) => {
        console.log('creationuser成功: ', data);
        this.users.push(data);
      },
      error: (err) => {
        console.error('creationuser失败: ', err);
      }
    });
}

2.4 发送 PUT request

PUT request用于updateserver on 现 has resource:

// user.service.ts
export class UserService {
  // ...

  // 发送 PUT requestupdateuser
  updateUser(id: number, user: any): Observable {
    return this.http.put(`${this.apiUrl}/${id}`, user);
  }
}

// componentinusing
updateUser() {
  const updatedUser = { name: '张三', email: 'zhangsan@example.com' };
  this.userService.updateUser(1, updatedUser)
    .subscribe({
      next: (data) => {
        console.log('updateuser成功: ', data);
        const index = this.users.findIndex(user => user.id === 1);
        if (index !== -1) {
          this.users[index] = data;
        }
      },
      error: (err) => {
        console.error('updateuser失败: ', err);
      }
    });
}

2.5 发送 DELETE request

DELETE request用于deleteserver on resource:

// user.service.ts
export class UserService {
  // ...

  // 发送 DELETE requestdeleteuser
  deleteUser(id: number): Observable {
    return this.http.delete(`${this.apiUrl}/${id}`);
  }
}

// componentinusing
deleteUser(id: number) {
  this.userService.deleteUser(id)
    .subscribe({
      next: () => {
        console.log('deleteuser成功');
        this.users = this.users.filter(user => user.id !== id);
      },
      error: (err) => {
        console.error('deleteuser失败: ', err);
      }
    });
}

3. requestconfiguration

可以throughconfigurationobject自定义 HTTP request:

// user.service.ts
export class UserService {
  // ...

  // 带configuration  GET request
  getUsersWithConfig(): Observable {
    const options = {
      headers: {
        'Authorization': 'Bearer ' + localStorage.getItem('token'),
        'Content-Type': 'application/json'
      },
      params: {
        page: '1',
        limit: '10'
      }
    };
    return this.http.get(this.apiUrl, options);
  }
}

4. errorprocessing

Angular HTTP 客户端providing了 many 种方式processing HTTP requesterror.

4.1 basicerrorprocessing

// componentinusing
this.userService.getUsers()
  .subscribe({
    next: (data) => {
      this.users = data;
    },
    error: (err) => {
      console.error('request失败: ', err);
      // processingerror, 例such as显示errorinformation
      this.error = `request失败: ${err.message}`;
    },
    complete: () => {
      console.log('requestcompletion');
    }
  });

4.2 using catchError operation符

可以using RxJS catchError operation符 in serviceinprocessingerror:

// user.service.ts
import { catchError } from 'rxjs/operators';
import { throwError } from 'rxjs';

export class UserService {
  // ...

  getUsers(): Observable {
    return this.http.get(this.apiUrl)
      .pipe(
        catchError(this.handleError)
      );
  }

  // errorprocessingmethod
  private handleError(error: any) {
    console.error('发生error: ', error);
    // 可以根据errorstatus码for不同 processing
    let errorMessage = '未知error';
    if (error.error instanceof ErrorEvent) {
      // 客户端error
      errorMessage = `客户端error: ${error.error.message}`;
    } else {
      // servererror
      errorMessage = `servererror: ${error.status} - ${error.message}`;
    }
    return throwError(errorMessage);
  }
}

5. HTTP 拦截器

HTTP 拦截器允许 in request发送 before and response返回 after for拦截 and processing, 例such as添加authenticationtoken, processingerror, 添加common头informationetc..

5.1 creation拦截器

ng generate interceptor auth

5.2 implementation拦截器

// auth.interceptor.ts
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, Httpprocessingr, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
  constructor() { }

  intercept(request: HttpRequest, next: Httpprocessingr): Observable> {
    // 获取token
    const token = localStorage.getItem('token');
    
    if (token) {
      // clonerequest并添加 Authorization 头
      const clonedRequest = request.clone({
        headers: request.headers.set('Authorization', 'Bearer ' + token)
      });
      // 继续processingrequest
      return next.handle(clonedRequest);
    }
    
    // 没 has token, 直接processingrequest
    return next.handle(request);
  }
}

5.3 register拦截器

// app.module.ts
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
  providers: [
    {
      provide: HTTP_INTERCEPTORS,
      useClass: AuthInterceptor,
      multi: true // 允许 many 个拦截器
    }
  ],
  // ...
})
export class AppModule { }

6. request取消

可以using HttpCancelToken 取消正 in for HTTP request:

// user.service.ts
import { HttpClient, HttpCancelTokenSource } from '@angular/common/http';

export class UserService {
  private cancelTokenSource: HttpCancelTokenSource;

  constructor(private http: HttpClient) { }

  getUsers(): Observable {
    // creation new  取消tokensources
    this.cancelTokenSource = this.http.cancelToken.source();
    
    return this.http.get(this.apiUrl, {
      cancelToken: this.cancelTokenSource.token
    });
  }

  // 取消request method
  cancelRequest() {
    if (this.cancelTokenSource) {
      this.cancelTokenSource.cancel('request已取消');
    }
  }
}

7. class型security

可以using TypeScript interface确保 API response class型security:

// user.interface.ts
export interface User {
  id: number;
  name: string;
  username: string;
  email: string;
  address: {
    street: string;
    suite: string;
    city: string;
    zipcode: string;
    geo: {
      lat: string;
      lng: string;
    }
  };
  phone: string;
  website: string;
  company: {
    name: string;
    catchPhrase: string;
    bs: string;
  };
}

// user.service.ts
import { User } from './user.interface';

export class UserService {
  // ...

  // 返回class型security  Observable
  getUsers(): Observable {
    return this.http.get(this.apiUrl);
  }
}

8. HTTP 客户端best practices

  1. 将 HTTP requestencapsulation in servicein, 不要直接 in componentin发送request
  2. using TypeScript interface确保 API response class型security
  3. implementation适当 errorprocessingmechanism
  4. using拦截器processingcommon逻辑, such asauthentication, log记录etc.
  5. 合理usingrequestconfiguration, such as添加头information, parameteretc.
  6. in component销毁时取消未completion request, 避免memory泄漏
  7. using RxJS operation符processingresponsedata, such as map, filter etc.
  8. for 于频繁request, 考虑usingcachemechanismreducingrequest次数

练习 1: implementationbasic HTTP request

  1. creation一个产品service, using Angular HTTP 客户端implementation以 under functions:
    • 获取产品list
    • 获取单个产品
    • creation new 产品
    • update产品
    • delete产品
  2. using JSONPlaceholder API serving asdatasources
  3. in componentinusing该service, 显示产品list, 并implementation添加, 编辑, delete产品 functions
  4. 添加适当 加载status and errorprocessing

练习 2: implementation HTTP 拦截器

  1. creation一个log拦截器, 记录所 has HTTP request and response
  2. creation一个errorprocessing拦截器, 统一processing HTTP requesterror
  3. register这些拦截器
  4. test拦截器 is 否正常工作