[英]Request is sent twice when intercepting http response
注意到当我们拦截HTTP响应并使用subscribe获取Observable响应中的值时,请求被触发了两次。
这是代码:
通过扩展拦截 Http 请求和响应 (http.service.ts)
import { Injectable } from '@angular/core';
import { Http, XHRBackend, RequestOptions, Request, RequestOptionsArgs, Response, Headers, ConnectionBackend } from '@angular/http';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/operator/map';
import 'rxjs/add/operator/catch';
import { LoggedInUserApi } from './loggedInUser.service';
@Injectable()
export class HttpService extends Http {
constructor(private loggedInUserApi: LoggedInUserApi, backend: XHRBackend, options: RequestOptions) {
super(backend, options);
}
request(url: string | Request, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.request(url, options));
}
get(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.get(url, options));
}
post(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.post(url, body, options));
}
put(url: string, body: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.put(url, body, options));
}
delete(url: string, options?: RequestOptionsArgs): Observable<Response> {
return this.intercept(super.delete(url, options));
}
handleResponseHeader(header) {
console.log(header);
}
intercept(observableResponse: Observable<Response>): Observable<Response> {
observableResponse.subscribe(response => this.handleResponseHeader(response.headers));
return observableResponse;
}
}
我相信订阅可观察的响应是导致问题的原因。 如果我们使用 .subscribe 的 .map instad,则没有问题是可重现的,但无法获得所需的结果,例如响应不会返回标头值
在 app.module.ts 中我们指定使用 HttpService 而不是 Http (app.module.ts)
.....
providers: [
......
{
provide: Http,
useFactory: (loggedInUserApi: service.LoggedInUserApi, xhrBackend: XHRBackend, requestOptions: RequestOptions) =>
new service.HttpService(loggedInUserApi, xhrBackend, requestOptions),
deps: [service.LoggedInUserApi, XHRBackend, RequestOptions]
}
],
....
在服务中,我们使用 post 方法调用服务器 API 来添加用户。 这个 API 调用进行了两次,这就是问题所在。 它应该只触发一次。 (用户操作.service.ts)
public addUser(body: models.User, extraHttpRequestParams?: any): Observable<models.User> {
// verify required parameter 'body' is not null or undefined
if (body === null || body === undefined) {
throw new Error('Required parameter body was null or undefined when calling addUser.');
}
const path = this.basePath + '/user';
let queryParameters = new URLSearchParams();
let headerParams = new Headers({ 'Content-Type': 'application/json' });
let requestOptions: RequestOptionsArgs = {
method: 'POST',
headers: headerParams,
search: queryParameters
};
requestOptions.body = JSON.stringify(body);
return this.http.request(path, requestOptions)
.map((response: Response) => {
if (response.status === 204) {
return undefined;
} else {
return response.json();
}
}).share();
}
在用户组件中,我们使用按钮单击事件调用服务并传递用户模型。 (用户.component.ts)
addUser(event) {
// To add user using api
this.busy = this.api.addUser(this.user)
.subscribe(
() => {
DialogService.displayStatusMessage({ message: 'User configurations saved successfully.', type: 'success' });
this.router.navigate(['users']);
},
(error: any) => {
throw ({ message: error.json().message });
}
);
}
我已经阅读了解释冷和热可观察的类似问题,我们应该使用 .share 使可观察变得热并避免这个问题。 我试过了,但我没有运气。
您的intercept
方法订阅了一个可观察对象,并返回它。 消费代码订阅了这个完全相同的 observable。
当涉及到与 Http 相关的 observable 时,两个订阅意味着两个 API 调用。
intercept(observableResponse: Observable<Response>): Observable<Response> {
observableResponse
.subscribe(response => // <-- pretty bad!
this.handleResponseHeader(response.headers)
);
return observableResponse;
}
您想要做的是使用用于副作用的.do()
运算符。 此运算符不修改 Observable 类型或事件值,只是“解包”它,对值执行一些工作,并将事件向下传递。
intercept(observableResponse: Observable<Response>): Observable<Response> {
return observableResponse
.do(response => this.handleResponseHeader(response.headers));
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.