简体   繁体   English

如何跟踪Angular HTTP POST调用进度

[英]How to track Angular HTTP POST call progress

I trying to put a progress bar in my http call but some how i wont be able to make a sync HTTP call request instead its going in async fashion. 我试图在我的http调用中放入一个进度条,但有些我怎么能够以异步方式进行同步HTTP调用请求。

below is function for making http call 以下是进行http调用的功能

 public authenticationt2cHTTP(email, password) {
    console.log("authenticationt2cHTTP WITH HEADERS");
    const body = new HttpParams()
      .set('email', email)
      .set('password', password);
    const req = new HttpRequest('POST', 'http://192.168.0.135:8080/rest/auth/login', body, {
      reportProgress: true,
      headers: new HttpHeaders().set('Content-Type', 'application/x-www-form-urlencoded')
    });

    this.http.request(req).subscribe(event => {
      // Via this API, you get access to the raw event stream.
      // Look for upload progress events.
      if (event.type === HttpEventType.UploadProgress) {
        // This is an upload progress event. Compute and show the % done:
        const percentDone = Math.round(100 * event.loaded / event.total);
        console.log(`File is ${percentDone}% uploaded.`);
      } else if (event instanceof HttpResponse) {
        console.log('File is completely uploaded!');
      }
    });

  }

below is code which i am using in my component class for making a call and showload is temp variable for showing/hiding preloader of the page. 下面是我在我的组件类中用于进行调用的代码,showload是用于显示/隐藏页面预加载器的临时变量。

this.showLoader = false;
      var k = this.myhttpService.authenticationt2c(this.form.get("email").value, this.form.get("password").value);
      this.showLoader = true;

I use the following http service wrapper to get access to different hooks like handleResponse , beforeRequest , afterResponse , onCatch & onSuccess . 我用下面的http服务包装以访问不同的钩子一样handleResponsebeforeRequestafterResponseonCatchonSuccess

The API services should consume the HttpInterceptor wrapper (which internally triggers the http call and gives access to above mentioned hooks). API服务应该使用HttpInterceptor包装器(它在内部触发http调用并提供对上述钩子的访问)。

Note how the loader logic is implemented in beforeRequest & afterResponse hooks. 注意装载机的逻辑是如何中实现beforeRequestafterResponse挂钩。

import { Injectable } from "@angular/core";
import { XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Http, Headers } from "@angular/http";
import { Store } from "@ngrx/store";
import { Observable } from "rxjs/Rx";
import { Observer } from "rxjs/Observer";
import { Response as ApiResponse } from "../../models/base/response.model";
import { ToastModel } from "../../redux/app-reducers";
import { ReducerActions } from "../../redux/reducer-actions";

@Injectable()
export class HttpInterceptor extends Http {
    constructor(private _XHRBackend: XHRBackend,
        private _RequestOptions: RequestOptions,
        private _ToastStore: Store<ToastModel>,
        private _LoaderStore: Store<boolean>) {
        super(_XHRBackend, _RequestOptions);
    }

    public request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
        return this.handleResponse(super.request(url, options));
    }

    public get(url: string, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url);
        return super.get(url, this.getRequestOptionArgs(options));
    }

    public post(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url, body);
        return super.post(url, body, this.getRequestOptionArgs(options));
    }

    public put(url: string, body: any, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url, body);
        return super.put(url, body, this.getRequestOptionArgs(options));
    }

    public delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
        this.beforeRequest(url);
        return super.delete(url, this.getRequestOptionArgs(options));
    }

    private getRequestOptionArgs(options?: RequestOptionsArgs): RequestOptionsArgs {
        if (options == null) {
            options = new RequestOptions();
        }
        if (options.headers == null) {
            options.headers = new Headers();
        }
        options.headers.append('Content-Type', 'application/json');

        return options;
    }

    private handleResponse(response: Observable<Response>): Observable<Response> {
        return response
            .catch(this.onCatch)
            .do(this.onSuccess.bind(this), this.onError.bind(this))
            .finally(this.afterResponse.bind(this));
    }

    private beforeRequest(url: string, body?: string): void {
        this._LoaderStore.dispatch({ type: ReducerActions.Loader.Set, payload: true });
    }

    private afterResponse(): void {
        this._LoaderStore.dispatch({ type: ReducerActions.Loader.Set, payload: false });
    }

    private onCatch(error: any, caught: Observable<Response>): Observable<Response> {
        console.log("interceptor catch called");
        return Observable.throw(error);
    }

    private onSuccess(res: Response): void {
        let response: ApiResponse<any> = res.json();
        if (!response.message) {
            return;
        }
        let toast: ToastModel = {
            text: response.message,
            duration: 5000,
            type: "success"
        };
        this._ToastStore.dispatch({ type: ReducerActions.Toast.Update, payload: toast });
    }

    private onError(error: any): void {
        let toast: ToastModel = {
            text: "Error occurred!",
            duration: 5000,
            type: "failure"
        };
        this._ToastStore.dispatch({ type: ReducerActions.Toast.Update, payload: toast });
    }
}

I hope this helps :) 我希望这有帮助 :)

As mentioned in comments, this is asynchronous, so while the request takes some time to execute, 正如评论中所提到的,这是异步的,所以虽然请求需要一些时间来执行,

this.showLoader = false;
// takes some time to execute
var k = this.myhttpService.authenticationt2c(...);
// executed while waiting for above code to execute
this.showLoader = true;

Instead, from your service, return an Observable and in component subscribe. 相反,从您的服务返回一个Observable并在组件订阅中。 Then inside the callback (subscribe) switch the boolean flag. 然后在回调(subscribe)内部切换布尔标志。 I'd guess that you would want to actually switch the boolean flag showLoader to false after the request have been completed, so I switched them around below: 我想你会想要在请求完成后将boolean标志showLoader切换为false ,所以我在下面切换它们:

this.showLoader = true;
this.myhttpService.authenticationt2c(...)
  .subscribe(() => this.showLoader = false)

and from the service, as said, return an Observable, so use map instead of subscribe : 从服务中,如上所述,返回一个Observable,所以使用map而不是subscribe

this.http.request(req).map(event => { ... })

Check these links for reading up on asynchronicity: How do I return the response from an Observable/http/async call in angular2? 查看这些链接以了解异步性: 如何从angular2中的Observable / http / async调用返回响应? and How do I return the response from an asynchronous call? 以及如何从异步调用返回响应?

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM