2016-05-16 26 views
0

雖然我與angular2一個小的障礙試驗處理chunke想出了:angular2 HTTP requist的反應

  • 我有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秒鐘後用以下代碼替換之前的消息:(準備運行!)

回答

1

您需要擴展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 }) 
]); 

查看此問題以瞭解更多詳情:

0

學習rxjs和閱讀Angular2源代碼後,我想出了這個解決方案

我覺得這是更好地使custom_backend,我認爲這是由角開發團隊推薦的方法。

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

在主要成分,我們必須提供自定義bakend是這樣的:當我們使用http.get()

providers: [ 
    HTTP_PROVIDERS, 
    PostSrevice, 
    MyBackend, 
    provide(XHRBackend, {useExisting:MyBackend}) 
] 

現在它會返回一個 Observable