How to use angular2 http API for tracking upload/d

2019-01-17 07:56发布

问题:

Tho there are many adhoc libraries supporting upload/download progress in angular2, I do not know how to do use native angular2 http api to show progress while doing upload/download.

The reason why I want to use native http api is because I want to utilise

  1. http interceptors(http API wrappers) around native http api that validate, cache & enrich the actual http request being sent such as this & this
  2. Besides angular's http api is much more robust than any adhoc APIs

There is this nice article about how to do upload/download using angular's http api

But the article mentions that there is no native way to support progress.

Did anyone try using http api for showing progress?

If not, do you know an issue in the angular repo for this?

回答1:

As of Angular 4.3.x and beyond versions, it can be achieved using the new HttpClient from @angular/common/http.

Read the Listening to progress events section.

Simple upload example (copied from the section mentioned above):

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

And for downloading, it might be something like pretty much the same:

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

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

Remember in case that you're monitoring a download, the Content-Length has to be set, otherwise, there's no way to the request to be measured.



回答2:

I would suggest using the native JavaScript XHR wrapped as an Observable, it's fairly easy to create on your own:

upload(file: File): Observable<string | number> {

    let fd: FormData = new FormData();

    fd.append("file", file);

    let xhr = new XMLHttpRequest;

    return Observable.create(observer => {

        xhr.addEventListener("progress", (progress) => {

            let percentCompleted;

            // Checks if we can really track the progress
            if (progress.lengthComputable) {

                // progress.loaded is a number between 0 and 1, so we'll multiple it by 100
                percentCompleted = Math.round(progress.loaded / progress.total * 100);

                if (percentCompleted < 1) {
                    observer.next(0);
                } else {
                    // Emit the progress percentage
                    observer.next(percentCompleted);
                }
            }
        });

        xhr.addEventListener("load", (e) => {

            if (e.target['status'] !== 200) observer.error(e.target['responseText']);

            else observer.complete(e.target['responseText']);
        });

        xhr.addEventListener("error", (err) => {

            console.log('upload error', err);

            observer.error('Upload error');
        });

        xhr.addEventListener("abort", (abort) => {

            console.log('upload abort', abort);

            observer.error('Transfer aborted by the user');
        });

        xhr.open('POST', 'http://some-dummy-url.com/v1/media/files');

        // Add any headers if necessary
        xhr.setRequestHeader("Authorization", `Bearer rqrwrewrqe`);

        // Send off the file
        xhr.send(fd);

        // This function will get executed once the subscription
        // has been unsubscribed
        return () => xhr.abort()
    });
}

And this is how one would use it:

// file is an instance of File that you need to retrieve from input[type="file"] element
const uploadSubscription = this.upload(file).subscribe(progress => {
    if (typeof progress === Number) {
        console.log("upload progress:", progress);
    }
});

// To abort the upload
// we should check whether the subscription is still active
if (uploadSubscription) uploadSubscription.unsubscribe();