Sử dụng ứng dụng HTTP Client của Angular v4

Với việc phát hành Angular v4.3 vào tháng 7, một số tính năng mới vừa được giới thiệu, trong số đó là HttpClientModule,  @angular/common/http thay thế @angular/http nhỏ gọn hơn, dễ dàng hơn và là một thư viện để thực hiện các yêu cầu HTTP.

Một dịch vụ HttpClient mới cũng đã có trong HttpClientModule và nó có thể được sử dụng để bắt đầu yêu cầu HTTP. Trong hướng dẫn này, tôi sẽ chỉ cho bạn triển khai ứng dụng mới này và kiểm tra một số tính năng của nó.

Chúng tôi đã nói về HTTP Client theo chiều sâu trong một bài viết trước: Angular 2 HTTP Requests with Observables

TLDR

Dưới đây là những thay đổi bạn cần thực hiện từ phiên bản cũ (trước phiên bản 4) sang phiên bản mới (v4+)

Để nhập vào một NgModule:

// below v4 ==========================================
import { HttpModule } from '@angular/http';

...
@NgModule({
    imports: [
        HttpModule
    ]
})
...

// v4+ ===============================================
import { HttpClientModule } from '@angular/common/http';

...
@NgModule({
    imports: [
        HttpClientModule
    ]
})
...

Và để sử dụng bên trong dịch vụ:

// below v4 ==========================================
import { Http } from '@angular/http';

...
constructor(private http: Http) {}
...

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

...
constructor(private http: HttpClient) {}
...

Chúng ta hãy xem xét sâu hơn.

Cài đặt Angular v4

Để bắt đầu cài đặt Angular CLI sử dụng Node và NPM nếu bạn chưa cài đặt nó.

npm install -g @angular/cli@latest

Các -gchuyển đổi để cài đặt nó trên toàn cầu và @latest cho phiên bản mới. Sau khi quá trình cài đặt hoàn tất, hãy chạy lệnh sau để chèn một ứng dụng mới

ng new httptutorial

Thao tác này sẽ tải template của dự án và cài đặt tất cả. Cấu trúc thư mục dự án sẽ giống như thế này.

// end-to-end-tests
|- e2e/
  |----- app.e2e-spec.ts
  |----- app.po.ts
  |----- tsconfig.e2e.json

// npm dependencies
|- node_modules/

// public facing app. built things go here. this wont show until we run a build
|- dist/

// where most of the work will be done
|- src/
  |----- app/
      |----- app.component.css|html|spec.ts|ts
      |----- app.module.ts
  |----- assets/
  |----- environments/
      |----- environment.prod.ts|ts
  |----- favicon.ico
  |----- index.html
  |----- main.ts
  |----- polyfills.ts
  |----- styles.css
  |----- test.ts
  |----- tsconfig.app.json
  |----- tsconfig.spec.json
  |----- typings.d.ts

// overall configuration
|- .angular-cli.json  // the main configuration file
|- .editorconfig      // editorconfig which is used in some VS Code setups
|- .gitignore
|- karma.conf.js
|- package.json
|- protractor.conf.js
|- README.md
|- tsconfig.json
|- tslint.json

Mở tập tin package.jsonvà cập nhật sự phụ thuộc vào phiên bản 4.3.6. Vì vậy, dependencies và devDependenciessection của tập tin như thế này:

"dependencies": {
    "@angular/animations": "^4.3.6",
    "@angular/common": "^4.3.6",
    "@angular/compiler": "^4.3.6",
    "@angular/core": "^4.3.6",
    "@angular/forms": "^4.3.6",
    "@angular/http": "^4.3.6",
    "@angular/platform-browser": "^4.3.6",
    "@angular/platform-browser-dynamic": "^4.3.6",
    "@angular/router": "^4.3.6",
    "core-js": "^2.4.1",
    "rxjs": "^5.4.2",
    "zone.js": "^0.8.14"
  },
  "devDependencies": {
    "@angular/cli": "1.3.2",
    "@angular/compiler-cli": "^4.3.6",
    "@angular/language-service": "^4.3.6",
    "@types/jasmine": "~2.5.53",
    "@types/jasminewd2": "~2.0.2",
    "@types/node": "~6.0.60",
    "codelyzer": "~3.1.1",
    "jasmine-core": "~2.6.2",
    "jasmine-spec-reporter": "~4.1.0",
    "karma": "~1.7.0",
    "karma-chrome-launcher": "~2.1.1",
    "karma-cli": "~1.0.1",
    "karma-coverage-istanbul-reporter": "^1.2.1",
    "karma-jasmine": "~1.1.0",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.1.2",
    "ts-node": "~3.2.0",
    "tslint": "~5.3.2",
    "typescript": "~2.3.3"
  }

Tiếp đó, chạy file project directory

npm install

Điều này sẽ kéo các dependences vào file package.json. Để xem nếu mọi thứ hoạt động đúng, bắt đầu chạy development web server:

ng serve

Điều này bắt đầu phát triển web server tại http://localhost:4200. Truy cập link url, và bạn sẽ thấy một cái gì đó như sau:

Cài đặt HTTP module

Tiếp theo, nhập HttpClientModule vào phần mô-đun gốc của ứng dụng tệp src/app/app.module.ts và thêm nó vào thuộc tính imports. Vì vậy, các tập tin trông như thế này:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

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

import { AppComponent } from './app.component';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Bây giờ các HttpClient để được sử dụng trong các component, nó cần phải được tiêm vào các nhà xây dựng lớp học. Trong src/app/app.component.ts nhập HttpClient sau đó đưa vào constructor như hình dưới đây:

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

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'app';

  constructor( private http: HttpClient ) { //dependency injection, creating an instance of HttpClient called http

  }
}

Bây giờ bạn sẽ có thể thực hiện các hoạt động CRUD và thực hiện các yêu cầu HTTP. Các phương thức HTTP khả dụng là post, put, delete, patch, head và jsonp.

HTTP GET

Để tìm ra phương pháp, chúng tôi sẽ truy hồi giả REST API. Đi qua link http://jsonplaceholder.typicode.com/ và cuộn xuống Resources. Bạn sẽ thấy một trang như sau:

Sau đó nhấp vào Resources/posts

Lưu ý rằng chúng ta thấy nhiều các đối tượng json ở đây, mỗi trong số đó có bốn thuộc tính: userIdidtitle and body. Vì vậy, khi chúng tôi nhấn vào link url: http://jsonplaceholder.typicode.com/posts từ ứng dụng Angular, chúng tôi sẽ nhận được kết quả trên. Các phương pháp HTTP khác cũng hoạt động như mong đợi.

Bây giờ, chỉnh sửa src/app/app.component.ts như sau:

import { Component, OnInit } from '@angular/core'; // importing the OnInit interface

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

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit { // implementing OnInit
  title = 'app';

  constructor( private http: HttpClient ) {

  }
  ngOnInit(): void { // adding the lifecycle hook ngOnInit
    this.http.get('http://jsonplaceholder.typicode.com/posts').subscribe(data => {
      console.log(data); // using the HttpClient instance, http to call the API then subscribe to the data and display to console
    });
  }

}

Ở đây chúng ta đang call đến điểm cuối API trong vòng đời ngOnInit. Hook này được gọi ra khi thành phần của chúng ta đã được khởi tạo. Đầu tiên chúng ta nhập giao diện OnInit, sau đó thực hiện giao diện này trong định nghĩa class. Sau đó chúng ta gọi phương thức ngOnInit, bên trong chúng ta gọi HttpClient instance http, chúng ta đã tạo ra trước đó trong constructor.

Chúng tôi gọi phương thức get từ trường hợp này, dự kiến URL của điểm cuối API mà chúng ta quan tâm. Phương thức get trả về một giá trị có thể quan sát được vì vậy chúng ta cần phải đăng ký với thông tin này để được thông báo khi đáp ứng đến, điều này được thực hiện bằng cách gọi phương pháp subscribe. Trong phương pháp subscribe, chúng ta đưa một trình xử lý sự kiện nhận dữ liệu, sau đó chúng ta có thể nhập vào bảng điều khiển. Đầu ra được hiển thị trong bảng điều khiển của trình duyệt sẽ giống như sau:

Đây là những đối tượng json được kéo từ url: http://jsonplaceholder.typicode.com/posts.

Để truy cập vào từng thuộc tính của đối tượng trả lời, ví dụ như thuộc tính data.userId, chúng ta cần phải gán đối tượng phản ứng vào một kiểu chứa các thuộc tính tương ứng. Để làm điều này, chúng ta hãy xác định một giao diện. Nhập các tệp tin sau vào tệp  src/app/app.component.ts ngay sau khi các câu lệnh nhập:

interface DataResponse {
  userId: string;
  id: string;
  title: string;
}

Tiếp theo, chỉnh sửa lệnh get call để sử dụng giao diện DataResponse:

this.http.get<DataResponse>('http://jsonplaceholder.typicode.com/posts/1').subscribe(data => {
      console.log('UserId: ' + data.userId);
      console.log('Id: ' + data.id);
      console.log('Title: ' + data.title);
      console.log('Body: ' + data.body);
    });

Bây giờ chúng ta có thể truy cập các thuộc tính userId, title và body riêng biệt. Đầu ra giao diện điều khiển sẽ giống như sau:

Chúng tôi có thể muốn hiển thị thông báo lỗi khi yêu cầu http thất bại. Để thực hiện việc này, đầu tiên hãy nhập HttpErrorResponse từ @angular/common/http sau đó tạo một hàm xử lý lỗi bằng cách thêm một callback vào phương thức subscribe, sau đó xác định một tham số kiểu HttpErrorResponse cho hàm xử lý lỗi:

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

// ...

this.http.get<DataResponse>('https://jsonplaceholder.typicode.com/posts/1').subscribe(data => {
      console.log('UserId: ' + data.userId);
      console.log('Id: ' + data.id);
      console.log('Title: ' + data.title);
      console.log('Body: ' + data.body);
    },
    (err: HttpErrorResponse) => {
      if (err.error instanceof Error) {
        console.log('Client-side error occured.');
      } else {
        console.log('Server-side error occured.');
      }
    }
  );

HTTP POST

Cũng như trước, chúng tôi sẽ sử dụng dịch vụ JSONPlaceholder để trình bày HTTP POST. Tuy nhiên, lưu ý rằng vì đây là một dịch vụ giả, dữ liệu không liên tục nhưng API đáp ứng như thể một API thực được gọi. Điểm cuối của yêu cầu POST là http://jsonplaceholder.typicode.com/posts. Nếu bạn truy cập url này, bạn sẽ thấy rằng chúng tôi có bốn tài sản có sẵn cho chúng tôi:userIdidtitle và body. Để sử dụng điểm cuối này để tạo một bản ghi mới, thêm một cuộc gọi thứ hai bên trong vòng đời của ngOnInit :

this.http.post('http://jsonplaceholder.typicode.com/posts', {
      title: 'foo',
      body: 'bar',
      userId: 1
    })
      .subscribe(
        res => {
          console.log(res);
        },
        err => {
          console.log('Error occured');
        }
      );

Phương pháp post  trả lại một lần nữa có thể giám sát vì vậy chúng ta cần phải đăng ký nhận xét này như trước, điều này được thực hiện bằng cách gọi phương thức đăng ký. Với phương pháp đăng ký, chúng ta hiểu một trình xử lý sự kiện nhận dữ liệu, sau đó chúng ta có thể in vào bảng điều khiển. Sau đó, chúng ta thêm trình xử lý lỗi để in thông tin nếu xảy ra lỗi. Đầu ra được hiển thị trong bảng điều khiển của trình duyệt sẽ giống như sau:

HTTP Interceptor

Một tính năng mới khác của mô đun HTTP Client là các interceptor. Interceptor nằm giữa ứng dụng và một backend API. Với interceptor chúng ta có thể đưa một yêu cầu đến từ ứng dụng trước khi nó thực sự được gửi và gửi đến backend. Cuộc trò chuyện cũng đúng, đó là phản ứng từ phía backend có thể thay đổi trước khi nó được gửi và xử lý bằng đơn của chúng tôi. Để thực hiện điều này, chúng tôi sẽ đánh chặn các thông tin tiêu đề đến từ yêu cầu nhận được để http://jsonplaceholder.typicode.com/posts/1. Trường header chúng ta sẽ thay đổi là trường Accept-Language đến từ API. Tạo một tệp mới src/app/typicode.interceptor.ts  và nhập mã sau:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Observable } from 'rxjs/observable';
@Injectable()
export class TypicodeInterceptor implements HttpInterceptor {
  intercept (req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    const authReq = req.clone({
      headers: req.headers.set('Accept-Language', 'Test')
    });
    return next.handle(authReq);
  }
}

Đầu tiên chúng ta nhập injectable từ @angular/core sau đó import HttpEventHttpInterceptorHttpHandler từ @angular/common/http. Cuối cùng, gói Observable  được import từ rxjs/observable.

Tiếp theo chúng ta thêm vào @injectable , sau đó tạo ra class TypicodeInterceptor thực thi giao diện HttpInterceptor. Sau đó chúng ta bổ sung phương thức interceptor trong việc thực hiện class.

Phương pháp này lấy một yêu cầu, thay đổi nó, trước khi chuyển nó sang cho việc xử lý tiếp đến ứng dụng của chúng tôi. Do đó chúng tôi đang đi qua hai tham số vào phương pháp này; yêu cầu bản thân của kiểuHttpRequest<any> và một tham số được gọi là next  đó là kiểu HttpHandler. Phương thức trả về một kiểu quan sát được của HttpEvent<any>

Tiếp theo chúng ta gọi phương thức req.clone() để nhân bản yêu cầu HTTP ban đầu. Bên trong phương pháp này chúng ta thay đổi trường tiêu đề được thực hiện bằng cách gọi phương thức req.headers.set(). Ở đây chúng ta thay đổi trường Accept-Language bằng cách thay đổi giá trị của nó thành Test.

Cuối cùng, đối tượng yêu cầu vừa được tạo ra (có header bao gồm) được chuyển tiếp để xử lý tiếp bằng cách sử dụng phương thức next.handle.

Người cung cấp Interceptor 

Để lấy interceptor để chúng tôi sử dụng chúng, chúng ta phải chỉnh sửa tập tin src/app/app.module.ts

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { HttpClientModule } from '@angular/common/http';
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AppComponent } from './app.component';
import { TypicodeInterceptor } from './typicode.interceptor';
@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    HttpClientModule
  ],
  providers: [{
    provide: HTTP_INTERCEPTORS,
    useClass: TypicodeInterceptor,
    multi: true
  }],
  bootstrap: [AppComponent]
})
export class AppModule { }

Ở đây chúng tôi đã nhập khẩu HTTP_INTERCEPTORS từ @angular/common/http và TypicodeInterceptor class chúng tôi tạo ra trước đó trong src/app/typicode.interceptor.ts. Tiếp theo, chúng ta chèn một đối tượng mới vào mảng được gán cho thuộc tính provider của @NgModule. Đối tượng này có ba thuộc tính:

  • provide: cần được đặt thành HTTP_INTERCEPTORS để xác định rằng một máy chủ chặn HTTP được cung cấp
  • useClass: cần phải được thiết lập để loại interceptor class của chúng tôi
  • multi: cần được đặt thành multi để nói với Angular rằng HTTP_INTERCEPTORS là một mảng các giá trị, chứ không phải là một giá trị duy nhất

Để xem interception này, hãy nhấp vào tab mạng, tải lại trang, sau đó chọn yêu cầu HTTP trên bảng điều khiển bên trái và các header HTTP sẽ được hiển thị trên bảng điều khiển bên phải. Yêu cầu chúng tôi quan tâm là yêu cầu nhận được gọi url: http://jsonplaceholder.typicode.com/posts/1.

Kết luận

Mô-đun HTTP Client giúp dễ dàng xử lý các giao diện HTTP backend như của REST API. Để recap chúng ta đã đề cập đến các thiết lập cơ bản của HttpClientModule, đưa ra cách sử dụng phương thức get và post và chỉ ra cách sử dụng tính năng interceptor mới. Bạn có thể nghĩ đến một vài trường hợp sử dụng được các tính năng này sẽ được yêu cầu. Cũng hãy xem dự án này trên Github. Nếu bạn có bất kỳ thắc mắc hoặc băn khoăn gì, đừng ngần ngại gửi chúng dưới đây.

Topdev via Scotch