创建http请求服务的最佳方法?

时间:2017-12-07 07:21:50

标签: angular typescript angular-promise angular5 angular-observable

我创建了一个用于处理所有http请求的服务。它工作得很好。但我想知道我的方法是否有任何错误,并且还想知道其他好的方法,如可观察的?

request.service.js

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { of } from 'rxjs/observable/of';
import { catchError, map, tap } from 'rxjs/operators';

import { MessageService } from './message.service';

const httpOptions = {
    headers: new HttpHeaders({ 'Content-Type': 'application/x-www-form-urlencoded' })
};

interface IRequestOption {
    url: string;
    cxfgroup: string;
    endpoint: string;
    data: object;
}

interface IRequestBody {
    option: IRequestOption;
    log: string;
    error: string;
}

class HTTP {

    private messageService: MessageService;

    constructor(http, messageService, url: string, body: object, log: string, error: string) {
        this.callHTTP(http, url, body, log, error);
        this.messageService = messageService;
    }

    callHTTP(http, url, body, log, error) {
        return http.post(url, body, httpOptions).toPromise()
            .then(this.extractData)
            .catch(this.handleErrorPromise);
    }

    private extractData(res: Response) {
        // let body = res.json();
        // return body['data'] || {};
        return res || {};
    }

    private handleErrorPromise(error: Response | any) {
        console.error(error.message || error);
        return Promise.reject(error.message || error);
    }
}

class RequestFactory {
    private baseURL = 'https://app.domain.com/cxf/';
    /**
     * CXF ENPOINTS
     */
    private endpoints: any = {
        "auth": {
            "getcustomerkeys": "auth/getcustomerkeys"
        }
    };

    call(http, messageService, options: IRequestOption, log: string, error: string) {
        let url: string = options.url ? options.url : this.baseURL;
        if (this.endpoints.hasOwnProperty(options['cxfgroup'])) {
            url += this.endpoints[options.cxfgroup][options.endpoint];
        }

        return new HTTP(http, messageService, url, options.data, log, error);
    }
}

@Injectable()
export class RequestService {

    constructor(private http: HttpClient, private messageService: MessageService) { }

    post(request: IRequestBody) {
        let requestFactory = new RequestFactory();
        requestFactory.call(this.http, this.messageService, request.option, request.log, request.error);
    }

}
  

我正在使用以下代码调用此“post”方法。我想要的   一旦请求完成我想要显示一些设置承诺   消息。

this.requestService.post({
  option: {
    url: '',
     cxfgroup: 'auth',
      endpoint: 'getcustomerkeys',
       data: {
         userid: 'user@domain.com'
       }
  },
  log: 'login initiated!',
  error: 'customerKeyError'
});

2 个答案:

答案 0 :(得分:2)

HTTP服务

以下是我们在项目中使用的基于观察的方法:

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

@Injectable()
export class HttpService {
  constructor(private http: HttpClient) {}

  /**
   * Invoke function should be able to handle any HTTP request based on the @params
   */
  invoke(params): Observable<any> {
    if (params) {
      const method = params.method.toLowerCase();
      const { url, path, body, headers, query } = params;

      const requestURL = `${url}/${path}`;

      let request;
      let requestParams = new HttpParams();
      let requestHeaders = new HttpHeaders();

      /**
       * DEFAULT HEADERS
       */
      requestHeaders = requestHeaders.set('Content-Type', 'application/json');

      /**
       * CUSTOM HEADERS
       */
      if (headers) {
        for (const key in headers) {
          if (headers.hasOwnProperty(key)) {
            requestHeaders = requestHeaders.append(key, headers[key]);
          }
        }
      }

      /**
       * CUSTOM REQUEST QUERY (?key=value)
       */
      if (query) {
        for (const key in query) {
          if (query.hasOwnProperty(key)) {
            requestParams = requestParams.append(key, query[key]);
          }
        }
      }

      const requestOptions = {
        headers: requestHeaders,
        params: requestParams,
      };

      /**
       * HANDLE GET, POST etc. REQUESTS
       */
      if (method === 'get') {
        request = this.http[method](requestURL, requestOptions);
      } else if (method === 'post' || method === 'put') {
        request = this.http[method](
          requestURL,
          JSON.stringify(body),
          requestOptions,
        );
      } else if (method === 'delete') {
        request = this.http.request(method, requestURL, {
          ...requestOptions,
          body: JSON.stringify(body),
        });
      } else {
        console.error('Unknown request method.');
      }

      /**
       * RETURN API REQUEST
       */
      return request;
    }
  }
}

服务中的使用示例

在您的服务中使用它非常简单,所以它看起来像这样:

constructor(private http: HttpService) {}

makeRequest() {
  return this.http.invoke({
    method: 'POST', // method like POST, GET etc.
    url: 'http://blabla', // base URL
    path: 'makeReq', // API endpoint
    body: ..., // body for POST or PUT requests
    headers: {headerName: 'HeaderValue'} // headers you need to add to your request
    query: {query: 'queryValue'} // URL query to be added (eg. ?query=queryValue)
  });
}

请注意,bodyheadersquery是可选的。

组件中的使用示例

最后,您需要订阅组件中的Observable来发出请求:

this.yourServiceName.makeRequest().subscribe(
  success => {
    // handle success
  },
  error => {
    // handle error
  }
);

错误处理

为了处理错误,我们可以使用HttpInterceptor,所以它看起来像这样:

import { Injectable } from '@angular/core';
import {
  HttpEvent,
  HttpInterceptor,
  HttpHandler,
  HttpRequest,
  HttpErrorResponse,
  HTTP_INTERCEPTORS,
} from '@angular/common/http';
import { Observable } from 'rxjs/Observable';
import { _throw } from 'rxjs/observable/throw';
import 'rxjs/add/operator/catch';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  intercept(
    req: HttpRequest<any>,
    next: HttpHandler,
  ): Observable<HttpEvent<any>> {
    return next.handle(req).catch(errorReponse => {
      let error: string;
      if (errorReponse instanceof HttpErrorResponse) {
        error = errorReponse.error;
        const { status, statusText, message } = errorReponse;
        const errMsg = `HTTP ERROR: ${status} - ${statusText}\n${message}\n\nBACKEND RESPONSE: `;
        console.error(errMsg, error);
      } else {
        error = null;
      }
      return _throw(error);
    });
  }
}

export const ErrorHttpInterceptor = {
  provide: HTTP_INTERCEPTORS,
  useClass: ErrorInterceptor,
  multi: true,
};

HttpInterceptor会将一些中间件功能应用于使用HttpClient提供程序进行的所有HTTP调用。请注意,它不适用于Http提供程序,因为它在最新版本中已弃用。并且不要忘记在@NgModule中包含拦截器:

@NgModule({
  providers: [ErrorHttpInterceptor]
})

可以使用类似的方法来注入Authorization令牌等。

答案 1 :(得分:1)

对不起Libu,它更简单&#34;简单&#34;比你的代码。你不需要创建类,类和类。此外,最好的方法是它始终返回一个Observable。实际上,使用promise而不是observable是没有优势的。如果你返回一个观察者,你可以&#34;链&#34; (使用switchMap),&#34; group&#34; (使用fork)等

@Injectable()
export class RequestService {
    private baseURL = 'https://app.domain.com/cxf/';
    constructor(private http: HttpClient)

    post(request: IRequestBody) {
        let url: string = options.url ? options.url : this.baseURL;
        if (this.endpoints.hasOwnProperty(options['cxfgroup'])) {
            url += this.endpoints[options.cxfgroup][options.endpoint];
        }
        let requestFactory = new RequestFactory();
        this.http.post(url,this.messageService, request.option)
        .do(console.log(request.log))  //when the request sucesfully
                                       //show in console
        .catch(console.log(request.error)); //if fail, show in console the error
    }
}