Подтвердить что ты не робот

Angular 2 Строка прогресса HTTP

В настоящее время существует способ в Angular 2 для получения прогресса (т.е. процентного значения) вызова ajax с использованием модуля angular2/http?

Я использую следующий код для выполнения своих HTTP-вызовов:

        let body = JSON.stringify(params);
        let headers = new Headers({ 'Content-Type': 'application/json' });
        let options = new RequestOptions({ headers: headers });
        this.http.post(url, body, options)
            .timeout(10000, new Error('Timeout exceeded during login'))
            .toPromise()
            .then((res) => {
                ...
            }).catch((err) => {
                ...
            });

Цель состоит в том, чтобы написать систему синхронизации. Сообщение вернет много данных, и я хочу дать пользователю указание о том, как долго будет выполняться синхронизация.

4b9b3361

Ответ 1

В настоящее время (из версии 4.3.0, при использовании нового HttpClient from @ngular/common/http) Angular обеспечивает прослушивание прогресса из коробки. Вам просто нужно создать объект HTTPRequest, как показано ниже:

import { HttpRequest } from '@angular/common/http';
...

const req = new HttpRequest('POST', '/upload/file', file, {
  reportProgress: true,
});

И когда вы подписываетесь на запрос, вы получите подписку на каждое событие прогресса:

http.request(req).subscribe(event => {
  // Via this API, you get access to the raw event stream.
  // Look for upload progress events.
  if (event.type === HttpEventType.UploadProgress) {
    // This is an upload progress event. Compute and show the % done:
    const percentDone = Math.round(100 * event.loaded / event.total);
    console.log(`File is ${percentDone}% uploaded.`);
  } else if (event instanceof HttpResponse) {
    console.log('File is completely uploaded!');
  }
});

Подробнее здесь.

Ответ 2

Вы можете использовать событие onprogress, предоставленное XHR (см. этот plunkr: http://plnkr.co/edit/8MDO2GsCGiOJd2y2XbQk?p=preview).

Это позволяет получить подсказки о ходе загрузки. Это не поддерживается с помощью Angular2, но вы можете подключить его расширенным классом BrowserXhr:

@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 })
]);

См. этот вопрос для получения дополнительной информации:

Ответ 3

Когда вы делаете http cals в angular2, он возвращает Observable типа Response, этот ответ создается внутри класса под названием XHRConnection где происходит вся магия.

XHRConnection создает ответ, слушая событие XMLHttpRequest load, это означает, что он вернет один ответ в конце запроса.

Теперь, чтобы иметь возможность изменить это поведение, нам нужно заставить наш класс подключения прослушивать событие progress.

Итак, нам нужно создать собственный класс Connection, чтобы обрабатывать ответ, как мы считаем нужным.

Я сделал это так, Обратите внимание, что мой php API возвращает несколько ответов в одном запросе, и эти ответы являются строками.

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);
  }
}

И в app.component.ts

import {Component, provide} from 'angular2/core';
import {HTTP_PROVIDERS,XHRBackend} from 'angular2/http';
import {MyBackend} from './my_backend';
@Component({
    selector: 'my-app',
    providers:  [
        HTTP_PROVIDERS,
        MyBackend,
        provide(XHRBackend, {useExisting:MyBackend})
    ]
    .
    .
    .

Теперь вызов http.get вернет пару ответов.

Ответ 4

Я настоятельно рекомендую использовать этот

https://www.npmjs.com/package/angular-progress-http

в противном случае возиться с xhr заставит вас пропускать сеансы cookie и других вещей

Кроме того, он будет более переносимым и проще реализовать