【问题标题】:How to make a generic request service in Angular8如何在 Angular8 中创建通用请求服务
【发布时间】:2020-04-15 18:43:33
【问题描述】:

我创建了一个通用请求服务,但它一直返回“ZoneAwarePromise”。我尝试使用 .pipe() 和 .subscribe() 来尝试检索请求的内容,但它不起作用。

requester.service.ts

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

@Injectable({
  providedIn: 'root'
})
export class RequesterService {

  constructor(private http: HttpClient) { }

  request(method, url, headers, body, params) {
    return this.http.request(method, url, {
      body: body || {},
      headers: headers || {},
      params: params || {}
    })
  }

  async get(url, params?, headers?, data?) {
    return await this.request('get', url, params, headers, data)
  }

  async post(url, params, headers, data) {
    return await this.request('post', url, params, headers, data);
  }

  async put(url, params, headers, data) {
    return await this.request('put', url, params, headers, data);
  }

  async delete(url, params, headers, data) {
    return await this.request('delete', url, params, headers, data);
  }
}

gym-list.component.ts

import { Component, OnInit } from '@angular/core';
import { RequesterService } from 'src/app/core/Requester/requester.service';

@Component({
  selector: 'app-gym-list',
  templateUrl: './gym-list.component.html',
  styleUrls: ['./gym-list.component.css']
})
export class GymListComponent implements OnInit {

  constructor(private Requester: RequesterService) { }

  ngOnInit() {
    console.log(this.teste())
  }

  async teste() {
    await this.Requester.get('https://searchs.glitch.me/proposalcontent')
  }
}

【问题讨论】:

  • 你试过没有asyncawait 在你的RequesterService 中的逻辑吗?我从来没有使用过那些带有 Observable 的东西,所以我首先想到的是什么可能会导致尝试使用管道和订阅。
  • Requester.get(url, ...)http.get(url, ...) 更容易吗?
  • 使用 async/await 并没有错,你开玩笑说必须将 observable 转换为 promise,并且 observable 有一个方法可以解决这个问题,请检查 m 答案是否适用于 ????????跨度>

标签: javascript angular typescript promise


【解决方案1】:
import { HttpClient, HttpHeaders, HttpRequest, HttpEventType, HttpEvent, HttpResponse, HttpErrorResponse } from "@angular/common/http";
import { Observable, from } from 'rxjs';
import { IGenericHttpClient } from './igeneric-http-client';
import { Injectable } from '@angular/core';
import { HttpMethod } from '../view-models/component-type.enum'
import { IRequestOptions } from '../view-models/interface';
import { EnvironmentViewModel } from '../view-models/environment-view-model';
import { retry } from 'rxjs/operators';
@Injectable()
export class GenericHttpClient<T> implements IGenericHttpClient<T>{

  constructor(private httpClient: HttpClient, private environment: EnvironmentViewModel) { }

  public Post(destinationUrl: string, options?: IRequestOptions): Observable<T> {
    return this.request<T>(HttpMethod.Post, destinationUrl, options);
  }

  public Put(destinationUrl: string, options?: IRequestOptions): Observable<T> {
    return this.request<T>(HttpMethod.Put, destinationUrl, options);
  }

  public Get(destinationUrl: string, options?: IRequestOptions): Observable<T> {
    return this.request<T>(HttpMethod.Get, destinationUrl, options);
  }

  public Delete(destinationUrl: string, options?: IRequestOptions): Observable<T> {
    return this.request<T>(HttpMethod.Delete, destinationUrl, options);
  }

  private request<T>(method: string, url: string, options?: IRequestOptions): Observable<T> {
    return Observable.create((observer: any) => {
      this.httpClient.request<T>(new HttpRequest(method, this.environment.baseUrl + url, options)).subscribe(
        (response: any) => {
          const responsTye = response as HttpEvent<any>
          switch (responsTye.type) {
            case HttpEventType.Sent:
              console.log('Request sent!');
              break;
            case HttpEventType.ResponseHeader:
              console.log('Response header received!');
              break;
            case HttpEventType.DownloadProgress:
              const kbLoaded = Math.round(responsTye.loaded / 1024);
              console.log(`Download in progress! ${kbLoaded}Kb loaded`);
              break;
            case HttpEventType.Response:
              observer.next(response.body);
              console.log('? Done!', responsTye.body);
          }
        },
        (error) => {
          switch (error.status) {
            case 403:
              observer.complete();
              break;
            default:
              observer.error(error);
              break;
          }
        }
      );
    });
  }
}

【讨论】:

    【解决方案2】:

    您正在尝试使用 await 返回一个非异步函数。

      request(method, url, headers, body, params) {
        return this.http.request(method, url, {
          body: body || {},
          headers: headers || {},
          params: params || {}
        })
      }
    
      async get(url, params?, headers?, data?) {
        return await this.request('get', url, params, headers, data)
      }
    

    你不应该在这里使用 async-await 系统。

    试试这个:

      get(url, params?, headers?, data?) {
        return this.request('get', url, params, headers, data)
      }
    

    并在您的 component.ts 文件中订阅此方法。

    像这样:

    Requester.get.subscribe(....)
    

    【讨论】:

      【解决方案3】:

      实际上,您可以创建一个可以在任何服务中扩展的抽象基础服务类。这将通过调用另一个具有通用错误处理代码的服务来自动处理错误。如果您传递customError 标志,则错误将返回到组件中以处理自定义错误。该方法使用RxJsObservables,可以在component.ts中订阅并捕获响应和错误。

      import { HttpClient, HttpHeaders } from "@angular/common/http";
      import { Observable } from "rxjs";
      import { tap } from "rxjs/operators";
      
      import { HttpOptionsService } from "../../services/httpoptions.service";
      
      export abstract class ServiceBase {
        constructor(
          private http: HttpClient,
          private httpOptionService: HttpOptionsService
        ) {}
      
        httpOptions = {
          headers: new HttpHeaders({
            "Content-Type": "application/json"
          })
        };
      
        getFormattedPostRequest(
          url: string,
          body: any,
          customError: boolean = false): Observable<any> {
          return this.pipeTapObservable(
            this.http.post(url, body, this.httpOptions),
            customError
          );
        }
      
        getFormattedPutRequest(
          url: string,
          body: any,
          customError: boolean = false
        ): Observable<any> {
          return this.pipeTapObservable(
            this.http.put(url, body, this.httpOptions),
            customError
          );
        }
      
        getFormattedGetRequest(
          url: string,
          customError: boolean = false
        ): Observable<any> {
          return this.pipeTapObservable(
            this.http.get(url, this.httpOptions),
            customError
          );
        }
      
        getFormattedDeleteRequest(
          url: string,
          customError: boolean = false
        ): Observable<any> {
          return this.pipeTapObservable(
            this.http.delete(url, this.httpOptions),
            customError
          );
        }
      
        private pipeTapObservable(
          request: Observable<any>,
          customError: boolean = false
        ): Observable<any> {
          return request.pipe(
            tap(
              response => response,
              error => {
                !customError &&
                  this.httpOptionService.handleError(error);
                return error;
              }
            )
          );
        }
      }
      

      如果您要添加一些常见的标头,您可以创建一个拦截器来添加它们。您可以在以下任何服务中使用它。

       @Injectable()
          export class MyService extends ServiceBase {
            constructor(
              http: HttpClient,
              httpOptionService: HttpOptionsService
          ) {
              super(http, httpOptionService);
            }
         }
      

      【讨论】:

        【解决方案4】:

        你可以使用 async/await,但是这种语法适用于 promise 类型,并且 request 方法返回一个 observable,所以你只需要从 request 方法返回一个 promise,或者你可以在 get,post,put 的 return 语句中执行它,删除方法

        import { Injectable } from '@angular/core';
        import { HttpClient } from '@angular/common/http';
        
        @Injectable({
          providedIn: 'root'
        })
        export class RequesterService {
        
          constructor(private http: HttpClient) { }
        
          request(method, url, headers, body, params) {
            return this.http.request(method, url, {
              body: body || {},
              headers: headers || {},
              params: params || {}
            }).toPromise();
          }
        
           get(url, params?, headers?, data?) {
            return this.request('get', url, params, headers, data);
          }
        
           post(url, params, headers, data) {
            return this.request('post', url, params, headers, data);
          }
        
           put(url, params, headers, data) {
            return this.request('put', url, params, headers, data);
          }
        
           delete(url, params, headers, data) {
            return this.request('delete', url, params, headers, data);
          }
        }
        

        组件

        import { Component, OnInit } from '@angular/core';
        import { RequesterService } from 'src/app/core/Requester/requester.service';
        
        @Component({
          selector: 'app-gym-list',
          templateUrl: './gym-list.component.html',
          styleUrls: ['./gym-list.component.css']
        })
        export class GymListComponent implements OnInit {
        
          constructor(private Requester: RequesterService) { }
        
          ngOnInit() {
            console.log(this.teste())
          }
        
          async teste() {
            const result = await this.Requester.get('https://searchs.glitch.me/proposalcontent');
        
            console.log(result); ?
          }
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2014-05-18
          • 2010-10-14
          • 2018-01-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-07-20
          相关资源
          最近更新 更多