创建 http 请求服务的最佳方法?
Best approach for creating http request service?
我创建了一项服务来处理所有 http 请求。它工作得很好。但是我想知道我的方法有没有错误,也想知道其他好的方法,比如 observable?
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);
}
}
I'm calling this "post" method using the following code. Here I want
to set a promise once the request complete i want to show some
message.
this.requestService.post({
option: {
url: '',
cxfgroup: 'auth',
endpoint: 'getcustomerkeys',
data: {
userid: 'user@domain.com'
}
},
log: 'login initiated!',
error: 'customerKeyError'
});
抱歉 Libu,它比您的代码更 "simple"。您不需要创建 class 和 class 以及 class。此外,最好的方法总是 return 和 Observable.Really 使用 promise 而不是 observable 没有任何优势。如果你return一个observable你可以"chain"(使用switchMap),"group"(使用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
}
}
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)
});
}
请注意 body
、headers
和 query
是可选的。
组件中的用法示例
最后,您需要在组件中订阅一个 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
令牌等
我创建了一项服务来处理所有 http 请求。它工作得很好。但是我想知道我的方法有没有错误,也想知道其他好的方法,比如 observable?
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);
}
}
I'm calling this "post" method using the following code. Here I want to set a promise once the request complete i want to show some message.
this.requestService.post({
option: {
url: '',
cxfgroup: 'auth',
endpoint: 'getcustomerkeys',
data: {
userid: 'user@domain.com'
}
},
log: 'login initiated!',
error: 'customerKeyError'
});
抱歉 Libu,它比您的代码更 "simple"。您不需要创建 class 和 class 以及 class。此外,最好的方法总是 return 和 Observable.Really 使用 promise 而不是 observable 没有任何优势。如果你return一个observable你可以"chain"(使用switchMap),"group"(使用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
}
}
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)
});
}
请注意 body
、headers
和 query
是可选的。
组件中的用法示例
最后,您需要在组件中订阅一个 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
令牌等