SoFunction
Updated on 2025-03-09

Exciting source code analysis of Angular HttpClient

Angular 4.3.0-rc.0 The version has been released 🐦. In this version, we waited for an exciting new feature - an improved version of the HTTPClient API, and mom would no longer have to worry about me handling HTTP requests in the future 😆.

HttpClient is an evolution of the existing Angular HTTP API, which is in a separate@angular/common/http In the package. This is to ensure that existing code bases can be migrated slowly to the new API.

Next let's start the new Angular versionHttp Client Journey.

Install

First, we need to update all packages to 4.3.0-rc.0 Version. Then, we need toAppModule Import inHttpClientModule Module. The details are as follows:

import { HttpClientModule } from '@angular/common/http';
@NgModule({
 declarations: [
  AppComponent
 ],
 imports: [
  BrowserModule,
  HttpClientModule
 ],
 bootstrap: [AppComponent]
})
export class AppModule { }

Now everything is ready. Let's experience three new features we've been looking forward to.

Feature 1 Default JSON parsing

Now JSON is the default data format, and we no longer need to perform explicit parsing. That is, we no longer need to use the following code:

(url).map(res => ()).subscribe(...)

Now we can write this:

(url).subscribe(...)

Feature 2 Support Interceptors

The interceptor allows us to insert middleware logic into the pipeline.

Request Interceptor

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

@Injectable()
class JWTInterceptor implements HttpInterceptor {
 
 constructor(private userService: UserService) {}
 
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

  const JWT = `Bearer ${()}`;
  req = ({
   setHeaders: {
    Authorization: JWT
   }
  });
  return (req);
 }
}

If we want to register a new interceptor, we need to implement it HttpInterceptor The interface is then implemented in the interface intercept method.

export interface HttpInterceptor {
 intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>>;
}

It should be noted that the request object and the response object must be immutable. Therefore, before we return the request object, we need to clone the original request object.

(req) The method uses the new request object, calls the underlying XHR object, and returns the response event stream.

Response Interceptor

@Injectable()
class JWTInterceptor implements HttpInterceptor {

 constructor(private router: Router) {}
 
 intercept(req: HttpRequest < any > ,
  next: HttpHandler): Observable < HttpEvent < any >> {

  return (req).map(event => {
    if (event instanceof HttpResponse) {
     if ( === 401) {
      // JWT expired, go to login
     }
    }
    return event;
   }
  }
}

The response interceptor can be passed in(req) The additional Rx operator is applied to the returned stream object (i.e., the Observable object) to transform the response event stream object.

Next, applyJWTInterceptor The last thing to respond to an interceptor is to register the interceptor, i.e.HTTP_INTERCEPTORS As a token, register a multi Provider:

[{ provide: HTTP_INTERCEPTORS, useClass: JWTInterceptor, multi: true }]

Feature 3 Progress Events

Progress events can be used to track file uploads and downloads.

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

(new HttpRequest(
 'POST',
  URL,
  body, 
 {
  reportProgress: true
 })).subscribe(event => {

 if ( === ) {
  // {
  // loaded:11, // Number of bytes uploaded or downloaded.
  // total :11 // Total number of bytes to upload or download
  // }
 }

 if ( === ) {
  // {
  // loaded:11, // Number of bytes uploaded or downloaded.
  // total :11 // Total number of bytes to upload or download
  // }
 }

 if ( === ) {
  ();
 }
})

If we want to track the progress of file upload or download, we need to configure it when creating the request object {reportProgress: true} parameter.

In addition, in the callback function, we pass To determine different event types, and perform corresponding event processing.

HttpEventTypeThe enumeration is defined as follows:

export enum HttpEventType {
 /**
   * Indicates that the request has been sent
   */
 Sent,

 /**
   * Upload progress event has been received
   */
 UploadProgress,

 /**
   * Response status code and response header have been received
   */
 ResponseHeader,

 /**
   * Download progress event has been received
   */
 DownloadProgress,

 /**
   * All responses have been received, including the response body
   */
 Response,

 /**
   * User-defined events, from interceptor or backend
   */
 User,
}

In fact, in addition to the three new functions mentioned above, there are also the following two new functions:

  1. Post-request verification and flush functions based on Angular internal testing framework
  2. Typed, synchronize response body access, including support for JSON response body types.

Finally, let’s further experience the above new features through the test cases in the client_spec.ts file.

Other features

Send a GET request

describe('HttpClient', () =&gt; {
  let client: HttpClient = null !;
  let backend: HttpClientTestingBackend = null !;
  beforeEach(() =&gt; {
   backend = new HttpClientTestingBackend();
   client = new HttpClient(backend);
  });
  afterEach(() =&gt; { (); }); // Request verification 
  describe('makes a basic request', () =&gt; {
   it('for JSON data', (done: DoneFn) =&gt; {
    ('/test').subscribe(res =&gt; {
     expect((res as any)['data']).toEqual('hello world');
     done();
    });
    ('/test').flush({'data': 'hello world'});
   });
   
   it('for an arraybuffer', (done: DoneFn) =&gt; {
    const body = new ArrayBuffer(4);
    // It also supports {responseType: 'text'}, {responseType: 'blob'}    ('/test', {responseType: 'arraybuffer'}).subscribe(res =&gt; {
     expect(res).toBe(body);
     done();
    });
    ('/test').flush(body);
   });
   
   it('that returns a response', (done: DoneFn) =&gt; {
    const body = {'data': 'hello world'};
    ('/test', {observe: 'response'}).subscribe(res =&gt; {
     expect(res instanceof HttpResponse).toBe(true);
     expect().toBe(body);
     done();
    });
    ('/test').flush(body);
   });
  });
});

Send a POST request

describe('makes a POST request', () => {
   it('with text data', (done: DoneFn) => {
    ('/test', 'text body', {observe: 'response', responseType: 'text'})
      .subscribe(res => {
       expect().toBeTruthy();
       expect().toBe(200);
       done();
      });
    ('/test').flush('hello world');
   });
 
   it('with json data', (done: DoneFn) => {
    const body = {data: 'json body'};
    ('/test', body, {observe: 'response', 
     responseType: 'text'}).subscribe(res => {
     expect().toBeTruthy();
     expect().toBe(200);
     done();
    });
    const testReq = ('/test');
    expect().toBe(body);
    ('hello world');
   });
});

Send a JSONP request

describe('makes a JSONP request', () => {
   it('with properly set method and callback', (done: DoneFn) => {
    ('/test', 'myCallback').subscribe(() => done());
    ({method: 'JSONP', url: '/test?myCallback=JSONP_CALLBACK'})
      .flush('hello world');
   });
});

Reference resources

A Taste From The New Angular HTTP Client

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.