+6

Tìm hiểu HttpClient trong angular 5

Hầu hết các ứng dụng giao tiếp với backend thông qua giao thức HTTP. Những trình duyệt hiện đại bây giờ đều hỗ trợ 2 API để tạo ra reqquests HTTP: XMLHttpRequest và "fetch()" API. Với HTTPCLIENT, @angular/common/http cung cấp một API đơn giản HTTP cho ứng dụng angular, xây dựng một interface XMLHttpRequest để giao tiếp với trình duyệt. Sự bổ sung của HttpClient là nó hỗ trợ khả năng kiểm tra tốt hơn, các request và response xử lý tốt hơn, hỗ trợ tốt hơn và cả việc handle error nưz.

Setup: installing the module

Để dùng HttpClient, bạn cần install HttpClientModule và provides nó vào app module.

// app.module.ts:

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

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

@NgModule({
  imports: [
    BrowserModule,
    // Include it under 'imports' in your application module
    // after BrowserModule.
    HttpClientModule,
  ],
})
export class MyAppModule {}

Chỉ cần import HttpClientModule là bạn có thể sử dụng bằng cách inject HttpClient vào component hay services.

Making a request for JSON data

Hầu hêts các request đến backend hiện nay đều là reqquest JSON data. Ví dụ: bạn có một API phụ trách một danh sách các item, /api/items sẽ trả về một object JSON như sau:

{
  "results": [
    "Item 1",
    "Item 2",
  ]
}

Phương thức get() của HttpClient sẽ truy cập dữ liệu này một cách đơn giản.

@Component(...)
export class MyComponent implements OnInit {

  results: string[];

  // Inject HttpClient into your component or service.
  constructor(private http: HttpClient) {}

  ngOnInit(): void {
    // Make the HTTP request:
    this.http.get('/api/items').subscribe(data => {
      // Read the result field from the JSON response.
      this.results = data['results'];
    });
  }
}

Typechecking the response

trong ví dụ trên , data['results'] sẽ đưa ra một mảng các items. Nếu bạn gõ data.results , typescript sẽ tự làm đúng cú pháp bằng cách chuyển JSon thành một object là instance của ItemsResponse.

http.get<ItemsResponse>('/api/items').subscribe(data => {
  // data is now an instance of type ItemsResponse, so you can do this:
  this.results = data.results;
});

Reading the full response

response trả về dự liệu nhiều khi không nằm trong body mà nằm trong header hoặc status code mới là dự liệu bạn mong muốn . Để lấy những dữ liệu đó bạn thay '{observe: 'body'}' thành {observe: 'response'}.

http
  .get<MyJsonData>('/data.json', {observe: 'response'})
  .subscribe(resp => {
    // Here, resp is of type HttpResponse<MyJsonData>.
    // You can inspect its headers:
    console.log(resp.headers.get('X-Custom-Header'));
    // And access the body directly, which is typed as MyJsonData as requested.
    console.log(resp.body.someField);
  });

Error handling

Điều gì xả ra nếu request server fails hoặc do không có mạng kết nối đến server. HttpClient sẽ trả về lỗi thay cho một success response. Để handle nó bạn hãy thêm một error handler vào .subcribe();

http
  .get<ItemsResponse>('/api/items')
  .subscribe(
    // Successful responses call the first callback.
    data => {...},
    // Errors will call this callback instead:
    err => {
      console.log('Something went wrong!');
    }
  );

Getting error details

Phát hiện ra lỗi là một chuyện nhưng hc]a đủ, tốt hơn nếu biết lỗi thực sự xảy ra là gì. Thống số err trong callback là một HttpErrorResponse có chứa những thông tin về lỗi này.

Có 2 loại lỗi có thể xảy ra. Neeys backend trả về unsuccessfull (404, 500,...) thì httpclient sẽ nhận về một error. Nhưng nếu lỗi xảy ra trên client hoặc do mất kết nối trường truyền thì một Error cũng sẽ được thrown ra nhưng không là một thể hiện của HttpErrorResponse

Trong cả 2 trường hợp bạn có thể xác định lỗi thông qua HttpErrorResponse.

http
  .get<ItemsResponse>('/api/items')
  .subscribe(
    data => {...},
    (err: HttpErrorResponse) => {
      if (err.error instanceof Error) {
        // A client-side or network error occurred. Handle it accordingly.
        console.log('An error occurred:', err.error.message);
      } else {
        // The backend returned an unsuccessful response code.
        // The response body may contain clues as to what went wrong,
        console.log(`Backend returned code ${err.status}, body was: ${err.error}`);
      }
    }
  );

Một cách để giải quyết lỗi là gửi lại request:. Có một toán tử .retry(), nó sẽ tự động subcribe lại vào Obserrvable. Đầu tiên cần import nó:

import 'rxjs/add/operator/retry';

Sau đó bạn dùng nó với HTTP Observables :

http
  .get<ItemsResponse>('/api/items')
  // Retry this request up to 3 times.
  .retry(3)
  // Any errors after the 3rd retry will fall through to the app.
  .subscribe(...);

Requesting non-JSON data

Không phải tất cả các API đều trả về JSON. Giả sự bạn muốn trả về một file text, httpclient sẽ expect một response textural.

http
  .get('/textfile.txt', {responseType: 'text'})
  // The Observable returned by get() is of type Observable<string>
  // because a text response was specified. There's no need to pass
  // a <string> type parameter to get().
  .subscribe(data => console.log(data));

Sending data to the server Making a POST request: Để gửi dữ liệu lên server sẽ dùng phương thức POST . Cách sử dụng phương thức Post cũng đơn giản như Get.

const body = {name: 'Brad'};

http
  .post('/api/developers/add', body)
  // See below - subscribe() is still necessary when using post().
  .subscribe(...);

Configuring other parts of the request:

URL và Body Param là những thông số cấu hình thông thường bạn hay dùng để gửi lên server. Ngoài ra cũng có nhiều khía cạnh khác bạn có thể cấu hình để request lên server. Headers Thông thường người ra sẽ thêm Authorization vào header của request.Bạn có thể làm như sau:

http
  .post('/api/items/add', body, {
    headers: new HttpHeaders().set('Authorization', 'my-auth-token'),
  })
  .subscribe();

URL Parameters

Thêm URL param có cách sử dụng cũng giống như trên. Để gửi id param với value là 3 bạn làm như sau:

http
  .post('/api/items/add', body, {
    params: new HttpParams().set('id', '3'),
  })
  .subscribe();

Theo cách này bạn sẽ có POST request tới URL như sau: /api/items/add?id=3.

Advanced usage

Từ đầu tới giờ chỉ là các chức năng cơ bản trong @angular/common/http nhưng đôi khi bạn cần thiết phải làm nhiều hơn là gửi yêu cầu và lấy dữ liệu.

Intercepting all requests or responses: interceptor sẽ xử lý tất cả các request trước khi trả về cho Obserable, nó sẽ là trung gian ở giữa chế biến dữ liệu rồi mới chuyển đi cho Subcriber. Writing an interceptor. Đẻ thực hiện một interceptor, bạn cần khai báo một class implements HttpInterceptor, và một function single intercept().

import {Injectable} from '@angular/core';
import {HttpEvent, HttpInterceptor, HttpHandler, HttpRequest} from '@angular/common/http';

import {Observable} from 'rxjs/Observable';

@Injectable()
export class NoopInterceptor implements HttpInterceptor {
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req);
  }
}

Providing your interceptor:

import {NgModule} from '@angular/core';
import {HTTP_INTERCEPTORS} from '@angular/common/http';

import {NoopInterceptor} from 'noop.interceptor.ts';

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

Immutability

Interceptors sẽ chặn và kieeurm tra dữ liệu của response những sẽ không làm thay đổi nó. Bạn có thể thực hiện điều naỳ bằng cách tạo ra bản sao:

intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
  // This is a duplicate. It is exactly the same as the original.
  const dupReq = req.clone();

  // Change the URL and replace 'http://' with 'https://'
  const secureReq = req.clone({url: req.url.replace('http://', 'https://')});
}

Bạn có thể thaáy clone() được sử dụng để tạo ra một bản copy với dữ liệu được thêm.

Configuring custom cookie/header names:

Nếu backend của bạn sử dụng các token và cookie riền để xử lý , ban có thể dùng HttpClientXsrfModule.withOptions() để thay đổi giá trị mặc định.

imports: [
  HttpClientModule,
  HttpClientXsrfModule.withOptions({
    cookieName: 'My-Xsrf-Cookie',
    headerName: 'My-Xsrf-Header',
  }),
]

Testing HTTP requests

HTTP backend sẽ mock data để phục vụ cho việc test và còn các thư viện @angular/common/http/testing nữa. Setup: import HttpClientTestingModule và thêm nó vào TestBed:

import {HttpClientTestingModule} from '@angular/common/http/testing';

beforeEach(() => {
  TestBed.configureTestingModule({
    ...,
    imports: [
      HttpClientTestingModule,
    ],
  })
});

Khi đó resquest sẽ gọi đến testing backend thay cho normal backend.

Expecting and answering requests

Với việc mock dữ liệu bạn có thể test kết quả của phương thức GET là dữ liệu mock của bạn. Đây là ví dụ:

it('expects a GET request', inject([HttpClient, HttpTestingController], (http: HttpClient, httpMock: HttpTestingController) => {
  // Make an HTTP GET request, and expect that it return an object
  // of the form {name: 'Test Data'}.
  http
    .get('/data')
    .subscribe(data => expect(data['name']).toEqual('Test Data'));

  // At this point, the request is pending, and no response has been
  // sent. The next step is to expect that the request happened.
  const req = httpMock.expectOne('/data');

  // If no request with that URL was made, or if multiple requests match,
  // expectOne() would throw. However this test makes only one request to
  // this URL, so it will match and return a mock request. The mock request
  // can be used to deliver a response or make assertions against the
  // request. In this case, the test asserts that the request is a GET.
  expect(req.request.method).toEqual('GET');

  // Next, fulfill the request by transmitting a response.
  req.flush({name: 'Test Data'});

  // Finally, assert that there are no outstanding requests.
  httpMock.verify();
}));

Trên đây là bài tìm hiểu của mình về HttpClient trong angular 5, các bạn có ý kiến đóng góp hãy comment bên dưới.😃


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí