انگولار - درخواست هنگام رهگیری پاسخ HTTP دوبار ارسال میشود
مشاهده شده است که درخواست دو بار فعال میشود وقتی ما پاسخ 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;
}
}
من معتقدم که اشتراک در پاسخ قابل مشاهده باعث بروز مشکل میشود. اگر از .map به جای .subscribe استفاده کنیم، هیچ مشکلی قابل بازتولید نیست اما نتیجه مورد نظر حاصل نمیشود، مانند اینکه مقادیر هدر از پاسخ برگشت داده نمیشوند.
در app.module.ts مشخص میکنیم که به جای Http از HttpService استفاده شود (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 دو بار انجام میشود و این مشکل است. باید تنها یک بار فعال شود. (User-operation.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();
}
در کامپوننت کاربر، ما سرویس را با استفاده از رویداد کلیک دکمه فراخوانی میکنیم و مدل کاربر را ارسال میکنیم. (User.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) مشترک میشود و آن را برمیگرداند. همین آبزرور دقیقاً توسط کد مصرفکننده مشترک میشود.
دو اشتراک به معنای دو فراخوانی API وقتی صحبت از مشاهدهای مرتبط با HTTP میشود، است.
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));
}
