【问题标题】:How to use angular2 http API for tracking upload/download progress如何使用 angular2 http API 跟踪上传/下载进度
【发布时间】:2017-07-03 00:52:15
【问题描述】:

虽然 angular2 中有许多支持上传/下载进度的临时库,但我不知道如何在上传/下载时使用原生 angular2 http api 来显示进度。

之所以要使用原生http api是因为我要使用

  1. http 拦截器(http API 包装器)围绕本地 http api 验证、缓存和丰富正在发送的实际 http 请求,例如 thisthis
  2. 除了 Angular 的 http api 比任何 adhoc API 更强大

this nice article 介绍了如何使用 Angular 的 http api 进行上传/下载

但是文章提到没有原生的方式来支持进度。

有没有人尝试使用 http api 来显示进度?

如果没有,您是否知道 Angular 存储库中有一个问题?

【问题讨论】:

  • 有人要求结束这个问题,说它太宽泛了。好吧,它不是。有没有人使用 Angular 的 http api 来跟踪进度?任何通用 Http API 都应该在此上下文中使用。它尽可能具体。

标签: http angular interceptor angular2-http


【解决方案1】:

我建议使用封装为 Observable 的原生 JavaScript XHR,它很容易自己创建:

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

这就是使用它的方式:

// 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();

【讨论】:

  • 编写自己的版本是我想避免的事情,我已经提到了为什么会出现这种情况
  • 例如,您的示例根本不处理取消订阅。除此之外,我将失去在发送请求之前以各种方式验证和丰富请求的拦截功能
  • 您无需取消订阅我的代码示例。我们在所有XHR 事件中调用completeerror,这些将自动取消订阅。请详细说明验证和丰富请求的含义。 Angular 的 http 目前不提供此功能,请查看 github.com/angular/angular/blob/master/modules/%40angular/http/…。有bytesLoadedtotalBytes,但尚未在任何地方使用。
  • wrt 完成/错误,如果用户在发送请求时单击不同的选项卡(它可能是一个应用程序具有这种行为是自然的),可以要求用户提示取消现有请求并转到单击的页面。在这种情况下,您需要取消订阅
【解决方案2】:

从 Angular 4.3.x 及更高版本开始,可以使用 @angular/common/http 中的新 HttpClient 来实现。

阅读Listening to progress events 部分。

简单的上传示例(从上面提到的部分复制):

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

对于下载,它可能几乎相同:

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

请记住,如果您正在监视下载,则必须设置 Content-Length,否则,无法测量请求。

【讨论】:

  • 在 4.1.x 上也为我工作
  • 你确定它是 4.1.x 吗?不仅在package.json 中,而且在上面提取的?
  • 嗨,我得到 event.total 为 undefined 不知道为什么?
  • @slartidan import { HttpClient } from '@angular/common/http'; constructor(private http: HttpClient)
  • 我可以补充一点,当使用 Angular 7.2.4 时,我需要 reportProgress: trueobserve: 'events' 来实际查看进度事件。只有observe: 'events' 不会执行下载/上传进度事件,而忽略observe 将默认为observe: 'body',它只返回响应的正文,不返回其他事件。
【解决方案3】:

现在可以实现了,请查看https://angular.io/guide/http#tracking-and-showing-request-progress

我可以在这里举个例子,但我认为 Angular 文档中的官方例子会更好

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-09
    相关资源
    最近更新 更多