1

我创建了一项服务来处理所有 http 请求。它运行良好。但我想知道我的方法有什么问题,还想知道其他好的方法,比如 observable?

请求服务.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);
    }

}

我正在使用以下代码调用此“发布”方法。在这里,我想在请求完成后设置一个承诺,我想显示一些消息。

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

2 回答 2

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

@NgModule({
  providers: [ErrorHttpInterceptor]
})

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

于 2017-12-07T07:56:03.330 回答
1

对不起 Libu,它比你的代码更“简单”。你不需要创建类和类和类。此外,最好的方法总是返回一个 Observable。使用 Promise 代替 Observable 确实没有任何优势。如果你返回一个 observable,你可以“链”(使用 switchMap)、“组”(使用 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
    }
}
于 2017-12-07T07:41:41.053 回答