Пока я экспериментировал с angular2, возникло небольшое препятствие:
У меня есть PHP-код ведьма возвращает куски ответов, используя «ob_flush».
В передний конец я успешно сделал «XHR = XMLHttpRequest«запрашивает и получает ответы и обрабатывает их с помощью»xhr.onprogress ()» а также «xhr.onreadystatechange ()».
Сейчас когда я пытался получить ту же функциональность, используя angular2 http.get (), Я не смог вывести результаты, когда они пришли с сервера! вместо этого результаты показаны угловыми в конце процесса после получения последнего ответа.
Я думаю, что объект rxjs Observer буферизует ответы!
Так как я могу изменить это поведение?
вот мой код php, testing.php:
echo date('H:i:s')." Loading data!";
ob_flush();
flush();
sleep(5);
echo "Ready to run!";
вот мой код angular2:
template: `
<div>
<h3>experimenting!</h3>
<button (click)="callServer()">run the test</button>
<div>the server says: {{msg}}</div>
</div>`
export class AppComponent {
msg:any;
constructor (private http:Http){}
callServer(){
this.http.get("localhost/testing.php")
.subscribe(res=> this.msg= res.text());
}
}
когда Я запускаю этот код, который он показывает через 5 секунд:
(19:59:47 Загрузка данных! Готов к запуску!).
Должен мгновенно вывести: (19:59:47 Загрузка данных!).
Затем через 5 секунд заменяет предыдущее сообщение на:(Готов к запуску!)
Вам нужно продлить BrowserXhr
класс, чтобы сделать это для настройки низкоуровневого объекта XHR:
@Injectable()
export class CustomBrowserXhr extends BrowserXhr {
constructor(private service:ProgressService) {}
build(): any {
let xhr = super.build();
xhr.onprogress = (event) => {
service.progressEventObservable.next(event);
};
return <any>(xhr);
}
}
и переопределить BrowserXhr
провайдер с расширенным:
bootstrap(AppComponent, [
HTTP_PROVIDERS,
provide(BrowserXhr, { useClass: CustomBrowserXhr })
]);
Смотрите этот вопрос для более подробной информации:
Изучив rxjs и прочитав исходный код Angular2, я пришел к этому решению
Я обнаружил, что лучше сделать custom_backend, я думаю, что это рекомендуемый подход Angular Dev Team.
my_backend.ts
import {Injectable} from "angular2/core";
import {Observable} from "rxjs/Observable";
import {Observer} from "rxjs/Observer";
import {Connection,ConnectionBackend} from "angular2/src/http/interfaces";
import {ReadyState, RequestMethod, ResponseType} from "angular2/src/http/enums";
import {ResponseOptions} from "angular2/src/http/base_response_options";
import {Request} from "angular2/src/http/static_request";
import {Response} from "angular2/src/http/static_response";
import {BrowserXhr} from "angular2/src/http/backends/browser_xhr";
import {Headers} from 'angular2/src/http/headers';
import {isPresent} from 'angular2/src/facade/lang';
import {getResponseURL, isSuccess} from "angular2/src/http/http_utils"
export class MyConnection implements Connection {
readyState: ReadyState;
request: Request;
response: Observable<Response>;
constructor(req: Request, browserXHR: BrowserXhr, baseResponseOptions?: ResponseOptions) {
this.request = req;
this.response = new Observable<Response>((responseObserver: Observer<Response>) => {
let _xhr: XMLHttpRequest = browserXHR.build();
_xhr.open(RequestMethod[req.method].toUpperCase(), req.url);
// save the responses in array
var buffer :string[] = [];
// load event handler
let onLoad = () => {
let body = isPresent(_xhr.response) ? _xhr.response : _xhr.responseText;
//_xhr.respons 1 = "Loading data!"//_xhr.respons 2 = "Loading data!Ready To Receive Orders."// we need to fix this proble
// check if the current response text contains the previous then subtract
// NOTE: I think there is better approach to solve this problem.
buffer.push(body);
if(buffer.length>1){
body = buffer[buffer.length-1].replace(buffer[buffer.length-2],'');
}
let headers = Headers.fromResponseHeaderString(_xhr.getAllResponseHeaders());
let url = getResponseURL(_xhr);
let status: number = _xhr.status === 1223 ? 204 : _xhr.status;
let state:number = _xhr.readyState;
if (status === 0) {
status = body ? 200 : 0;
}
var responseOptions = new ResponseOptions({ body, status, headers, url });
if (isPresent(baseResponseOptions)) {
responseOptions = baseResponseOptions.merge(responseOptions);
}
let response = new Response(responseOptions);
//check for the state if not 4 then don't complete the observer
if(state !== 4){
//this will return stream of responses
responseObserver.next(response);
return;
}
else{
responseObserver.complete();
return;
}
responseObserver.error(response);
};
// error event handler
let onError = (err: any) => {
var responseOptions = new ResponseOptions({ body: err, type: ResponseType.Error });
if (isPresent(baseResponseOptions)) {
responseOptions = baseResponseOptions.merge(responseOptions);
}
responseObserver.error(new Response(responseOptions));
};
if (isPresent(req.headers)) {
req.headers.forEach((values, name) => _xhr.setRequestHeader(name, values.join(',')));
}
_xhr.addEventListener('progress', onLoad);
_xhr.addEventListener('load', onLoad);
_xhr.addEventListener('error', onError);
_xhr.send(this.request.text());
return () => {
_xhr.removeEventListener('progress', onLoad);
_xhr.removeEventListener('load', onLoad);
_xhr.removeEventListener('error', onError);
_xhr.abort();
};
});
}
}
@Injectable()
export class MyBackend implements ConnectionBackend {
constructor(private _browserXHR: BrowserXhr, private _baseResponseOptions: ResponseOptions) {}
createConnection(request: Request):MyConnection {
return new MyConnection(request, this._browserXHR, this._baseResponseOptions);
}
}
В основном компоненте мы должны предоставить пользовательский пакет следующим образом:
providers: [
HTTP_PROVIDERS,
PostSrevice,
MyBackend,
provide(XHRBackend, {useExisting:MyBackend})
]
Сейчас когда мы используем http.get () это вернет поток наблюдаемого