在Angular 6中处理请求的开始和结束

时间:2018-10-18 12:03:18

标签: angular typescript

我用角度6写了一个serviceHelper。我想显示每个请求开始的加载图像,并在请求自动完成时关闭加载图像。因此,我需要在捕获到请求的开始和结束时使用eventHandler进行请求。 (也许捕获错误)。我创建一个加载程序拦截器。但是,拦截器无法捕获我的请求。

import { HttpClient, HttpParams } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import ServiceResult from '../models/common/service-result';

@Injectable({
  providedIn: 'root'
})
export class ServiceHelper {    
  constructor(private http: HttpClient) { }

  get<T>(modulePort, controllerName: string, methodName: string, params: HttpParams = null): Observable<ServiceResult<T>> {
      return this.http.get<ServiceResult<T>>("http://localhost:5001/api/" + controllerName + "/" + methodName, { params: params });
    }

  post<T>(modulePort, controllerName: string, methodName: string, postedObject): Observable<ServiceResult<T>> {
    return this.http.post<ServiceResult<T>>("http://localhost:5001/api/" + controllerName + "/" + methodName, postedObject);
  }
}

ServiceResult.ts

abstract class ServiceResult<T> {
  public abstract messages: string[];
  public abstract resultType: int;
  public abstract data: T;
}

export default ServiceResult;

loader-interceptor.ts

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

import { ServiceHelper } from '../helpers/service-helper';

@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
  private currentRequests: number;
  constructor(
    private _httpService: ServiceHelper) {
  }
  intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    debugger;
    if (this._httpService.ukljuciLoader) {
      console.log("Your request started");
      return next.handle(request)
        .pipe(
          tap((event: HttpEvent<any>) => {
          if (event instanceof HttpResponse) {
            console.log("Your request finished");
            }
          }, (err: any) => {
            console.log("You get an error.");
          })
        );
    } else {
      return next.handle(request);
    }
  }
}

export const LoaderInterceptorProvider = {
  provide: HTTP_INTERCEPTORS,
  useClass: LoaderInterceptor,
  multi: true
};

3 个答案:

答案 0 :(得分:1)

您应该为此目的创建拦截器。这是我的:

import { Injectable } from '@angular/core';
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor, HttpResponse, HTTP_INTERCEPTORS } from '@angular/common/http';
import { Observable } from 'rxjs';
import { tap } from 'rxjs/operators';

import { LoaderService } from './loader.service';
import { HttpService } from '../shared/http.service';

@Injectable()
export class LoaderInterceptor implements HttpInterceptor {
    private currentRequests: number;
    constructor(
        private _loaderService: LoaderService,
        private _httpService: HttpService) {
        this.currentRequests = 0;
    }
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        if (this._httpService.ukljuciLoader) {
            if (this._loaderService.autoloader) {
                this.incrementRequestCount();
            }
            return next.handle(request)
                .pipe(
                    tap((event: HttpEvent<any>) => {
                        if (event instanceof HttpResponse) {
                            if (this._loaderService.autoloader) {
                                this.decrementRequestCount();
                            }
                        }
                    }, (err: any) => {
                        if (this._loaderService.autoloader) {
                            this.currentRequests = 0;
                            this._loaderService._toggleLoader.emit(false);
                        }
                    })
                );
        } else {
            return next.handle(request);
        }
    }
    private decrementRequestCount() {
        if (--this.currentRequests === 0) {
            this._loaderService._toggleLoader.emit(false);
        }
    }

    private incrementRequestCount() {
        if (this.currentRequests++ === 0) {
            this._loaderService._toggleLoader.emit(true);
        }
    }
}

export const LoaderInterceptorProvider = {
    provide: HTTP_INTERCEPTORS,
    useClass: LoaderInterceptor,
    multi: true
};

这是html:

<div class="loader-wrapper" *ngIf="loader">
    <div class="loader"></div>
</div>

这是ts文件:

import { Component, OnInit, OnDestroy } from '@angular/core';
import { Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

import { LoaderService } from './loader.service';

@Component({
  selector: 'app-loader',
  templateUrl: './loader.component.html'
})
export class LoaderComponent implements OnInit, OnDestroy {
  private ngUnsubscribe: Subject<any> = new Subject();
  public loader = false;
  constructor(
    private _loaderService: LoaderService
  ) { }
  ngOnInit() {
    this._loaderService._toggleLoader
      .pipe(takeUntil(this.ngUnsubscribe))
      .subscribe(
        res => {
          setTimeout(() => { this.loader = res; });
        });
  }

  ngOnDestroy() {
    this.ngUnsubscribe.next();
    this.ngUnsubscribe.complete();
  }
}

加载程序服务:

import { Injectable, EventEmitter } from '@angular/core';

@Injectable()
export class LoaderService {
    public autoloader = true;
    public _toggleLoader: EventEmitter<any>;
    constructor() {
        this._toggleLoader = new EventEmitter<any>();
    }
    toggleLoader(toggle: boolean) {
        this._toggleLoader.emit(toggle);
    }
}

应用模块

....
import { LoaderInterceptor, LoaderInterceptorProvider } from './loader/loader.interceptor';

@NgModule({
  declarations: [
   ...
  ],
  imports: [
    ...
    LoaderModule,
    ...
  ],
  providers: [
   ...
    LoaderInterceptorProvider,
    ...
    }
  ],
  entryComponents: [..],
  bootstrap: [AppComponent]
})

export class AppModule {
}

最终的CSS

.loader-wrapper {
  position: fixed !important;
  top: 0;
  left: 0;    
  width: 100%;
  height: 100%;
  background-position: center center;
  background-color: rgba(255, 255, 255, 1);
  z-index: 9998;
}
.loader {
  position: relative;
  left: 50%;
  top: 50%;
  height: 20vw;
  width: 20vw;
  margin: -10vw 0 0 -10vw; 
  border: 3px solid transparent;
  border-top-color: #3498db;
  border-bottom-color: #3498db; 
  border-radius: 50%;
  z-index: 2;
  -webkit-animation: spin 2s linear infinite;
  -moz-animation: spin 2s linear infinite;
  -o-animation: spin 2s linear infinite;
  animation: spin 2s linear infinite;
}  
.loader:before {
  content: "";
  position: absolute;
  top:2%;
  bottom: 2%;
  left: 2%;
  right: 2%; 
  border: 3px solid transparent;
  z-index: 2;
  border-top-color: #db213a;
  border-radius: 50%;
  -webkit-animation: spin 3s linear infinite;
  -moz-animation: spin 3s linear infinite;
  -o-animation: spin 3s linear infinite;
  animation: spin 3s linear infinite; 
}  
.loader:after {
  content: "";
  position: absolute;
  top:5%;
  bottom: 5%;
  left: 5%;
  right: 5%; 
  border: 3px solid transparent;
  border-top-color: #dec52d;
  z-index: 2;
  border-radius: 50%;
  -webkit-animation: spin 1.5s linear infinite;
  -moz-animation: spin 1.5s linear infinite;
  -o-animation: spin 1.5s linear infinite;
  animation: spin 1.5s linear infinite;
}  
  /*Keyframes for spin animation */  
@-webkit-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(0deg);  /* IE 9 */
    transform: rotate(0deg);  /* Firefox 16+, IE 10+, Opera */
  }

  50% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(180deg);  /* Firefox 16+, IE 10+, Opera */
  }
  100% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(360deg);  /* Firefox 16+, IE 10+, Opera */
  }
}  
@-moz-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(0deg);  /* IE 9 */
    transform: rotate(0deg);  /* Firefox 16+, IE 10+, Opera */
  }

  50% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(180deg);  /* Firefox 16+, IE 10+, Opera */
  }
  100% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(360deg);  /* Firefox 16+, IE 10+, Opera */
  }
}  
@-o-keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(0deg);  /* IE 9 */
    transform: rotate(0deg);  /* Firefox 16+, IE 10+, Opera */
  }

  50% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(180deg);  /* Firefox 16+, IE 10+, Opera */
  }
  100% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(360deg);  /* Firefox 16+, IE 10+, Opera */
  }
}  
@keyframes spin {
  0% {
    -webkit-transform: rotate(0deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(0deg);  /* IE 9 */
    transform: rotate(0deg);  /* Firefox 16+, IE 10+, Opera */
  }

  50% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(180deg);  /* Firefox 16+, IE 10+, Opera */
  }
  100% {
    -webkit-transform: rotate(360deg);  /* Chrome, Opera 15+, Safari 3.1+ */
    -ms-transform: rotate(360deg);  /* IE 9 */
    transform: rotate(360deg);  /* Firefox 16+, IE 10+, Opera */
  }
}

当您不想加星时

这是我的http.service:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders, HttpParams } from '@angular/common/http';
import { Observable } from 'rxjs';

import { Url } from './global';

export interface IRequestOptions {
    headers?: HttpHeaders;
    observe?: 'body';
    params?: HttpParams;
    reportProgress?: boolean;
    responseType?: 'json';
    withCredentials?: boolean;
    body?: any;
}

export function httpServiceCreator(http: HttpClient) {
    return new HttpService(http);
}

@Injectable()
export class HttpService {
    ukljuciLoader: boolean;
    public constructor(public http: HttpClient) {
        // If you don't want to use the extended versions in some cases you can access the public property and use the original one.
        // for ex. this.httpClient.http.get(...)
    }

    public get<T>(url: string, options?: IRequestOptions, loader: boolean = true): Observable<T> {
        this.ukljuciLoader = loader;
        return this.http.get<T>(Url + url, options);
    }

    public post<T>(url: string, params: Object, options?: IRequestOptions, loader: boolean = true): Observable<T> {
        this.ukljuciLoader = loader;
        return this.http.post<T>(Url + url, params, options);
    }

    public put<T>(url: string, params: Object, options?: IRequestOptions, loader: boolean = true): Observable<T> {
        this.ukljuciLoader = loader;
        return this.http.put<T>(Url + url, params, options);
    }

    public delete<T>(url: string, options?: IRequestOptions, loader: boolean = true): Observable<T> {
        this.ukljuciLoader = loader;
        return this.http.delete<T>(Url + url, options);
    }
}
export const HttpServiceProvider = {
    provide: HttpService,
    useFactory: httpServiceCreator,
    deps: [HttpClient]
};

这是我要启动加载程序时的调用:

someCall( userid: number) {
        let bodyString = JSON.stringify(userid: userid );
        let headers = new HttpHeaders({ 'Content-Type': 'application/JSON' });
        return this._http.post<any>('serverapi/spme call', bodyString, { headers: headers });
    }

这是我不希望加载程序启动的时间:

someCall( userid: number) {
        let bodyString = JSON.stringify(userid: userid );
        let headers = new HttpHeaders({ 'Content-Type': 'application/JSON' });
        return this._http.post<any>('serverapi/spme call', bodyString, { headers: headers }, false);
    }

答案 1 :(得分:0)

您应该使用订阅角度HTTP服务结果。 代码示例;

get<T>(modulePort, controllerName: string, methodName: string, params: HttpParams = null): Observable<ServiceResult<T>> {
      return this.http.get<ServiceResult<T>>("http://localhost:5001/api/" + controllerName + "/" + methodName, { params: params }).subscribe(result=>result.json(), err=> console.log(err));
    }

,您可以查找包含您的http包装器的git repo; https://github.com/mehmetkarpuz/Angular6-http-wrapper

答案 2 :(得分:0)

  

这是可以使用HttpInterceptor的最佳方案。

LoaderInterceptorService

import { Injectable, Injector } from '@angular/core';
import { HttpEvent, HttpInterceptor, HttpHandler, HttpRequest, HttpResponse } from '@angular/common/http';
import { Observable, pipe } from 'rxjs';
import { tap } from 'rxjs/operators';
@Injectable({
  providedIn: 'root'
})
export class LoaderInterceptorService implements HttpInterceptor {
  constructor() { }
  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    this.showLoader();
    return next.handle(req).pipe(tap((event: HttpEvent<any>) => { 
      if (event instanceof HttpResponse) {
        this.onEnd();
      }
    },
      (err: any) => {
        this.onEnd();
    }));
  }
  private onEnd(): void {
    this.hideLoader();
  }
  private showLoader(): void {
   //show the image here
  }
  private hideLoader(): void {
   //hide the image
  }
}

AppModule

import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { LoaderInterceptorService } from './_services/loader-interceptor.service';
...
providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: LoaderInterceptorService,
    multi: true
  }
]