Azure 存储 javascript 客户端:如何使用 Ionic/Angular 跟踪上传进度?

Azure storage javascript client: how to track upload progress using Ionic/Angular?

在此 guideline 之后,我想通过将 progress 值设为 DOM 来跟踪上传进度。我还想在上传完成后在 DOM 中打印 'done'。有没有办法“订阅”SpeedSummary 以便我可以获得它的进度值?还有其他更推荐的方法吗?

我的代码:

      var finishedOrError = false;
      
      var speedSummary = blobService.createBlockBlobFromBrowserFile('input-data', filename, file, {blockSize : customBlockSize}, function(error, result, response) {
        finishedOrError = true;
        if (error) {
            // Upload blob failed
            alert('Problema: Volver a intentar o contactar al administrador');
        } else {
            // Upload successfully
            alert('Subida Exitosa');
            finish_upload();
            return result;
        }
      });
      
      speedSummary.on('progress', function () {
        var process = speedSummary.getCompletePercent();
        displayProcess(process);
      })

      var finish_upload = function(){
        //TODO set upload finish process
        //this.isUploading = false; DOESN'T WORK SINCE this is speedSummary in this context
      }
      var displayProcess = function(process){
        //TODO set progress indicator
      }

注意:我知道这个 implementation 但是在实现 uploadFile 函数时它给我一个错误。但更重要的是,我正在寻找更直接的实现方式。

注2:上面提到的错误是

No overload matches this call.
  Overload 1 of 11, '(op1: UnaryFunction<Observable<number>, Observable<unknown>>, op2: UnaryFunction<Observable<unknown>, Observable<number>>): Observable<...>', gave the following error.
    Argument of type 'Observable<number>' is not assignable to parameter of type 'UnaryFunction<Observable<number>, Observable<unknown>>'.

如果想在angular应用中上传blob时跟踪上传进度,可以使用新的nodejs存储sdk@azure/storage-blob来实现。

例如

  1. 创建一个 angular 网络应用程序
ng new <appname>
  1. 安装 Azure 存储 SDK
npm install @azure/storage-blob
  1. 更新app.component.html文件
<div class="mainContainer">
  <div class="content">
      <div class="header">
          <h1>Angular File Upload</h1>
      </div>
      <div class="form-group">
        <label for="file">Choose File</label>
        <input type="file"
               id="file"
               (change)="onFileChange($event)">
        <p> progress is = {{progress}} </p>
        <p>result: {{status}}</p>
      </div>
  </div>
</div>


  1. 在polyfills.ts
  2. 中添加如下代码
(window as any).global = window;
(window as any).process = require( 'process' );
(window as any).Buffer = require( 'buffer' ).Buffer;
  1. 在app.component.ts
  2. 中添加如下代码
import { Component } from '@angular/core';
import {BlobServiceClient,AnonymousCredential,newPipeline } from '@azure/storage-blob';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  title = 'web1';
  currentFile : File =null;
  onFileChange(event) {
    this.currentFile = event.target.files[0];
    this.upload();
 }

 async upload(){
     const accountName ="andyprivate";
      const sasToken="";
      const containerName="test";
      
      const pipeline =newPipeline (new AnonymousCredential(),{
      retryOptions: { maxTries: 4 }, // Retry options
      userAgentOptions: { userAgentPrefix: "AdvancedSample V1.0.0" }, // Customized telemetry string
      keepAliveOptions: { enable: false}
      });

      const blobServiceClient =new BlobServiceClient(`https://${accountName}.blob.core.windows.net?${sasToken}`,
                                                      pipeline  )
      const containerClient =blobServiceClient.getContainerClient(containerName)
                if(!containerClient.exists()){
                console.log("the container does not exit")
                await containerClient.create()

                }
     const client = containerClient.getBlockBlobClient(this.currentFile.name)
     await client.uploadBrowserData(this.currentFile,{
                      blockSize: 4 * 1024 * 1024, // 4MB block size
                      concurrency: 20, // 20 concurrency
                      onProgress: (ev) => {
                        console.log(`you have upload ${ev.loadedBytes} bytes`);
                        this.progress= (ev.loadedBytes/this.currentFile.size)*100;
                    
                    },
                      blobHTTPHeaders :{blobContentType:this.currentFile.type}
       }).then(response =>{
                        console.log(response)
                        if(response.errorCode !=null){
                          console.log("failed")
                          this.status="fail";
                        }
                        this.status="done";
                      })
        
 }
}

  1. 通过 Azure 门户在 Azure 存储帐户中配置 CORS。详情请参考document
Allowed origins: *
Allowed verbs: DELETE,GET,HEAD,MERGE,POST,OPTIONS,PUT
Allowed headers: *
Exposed headers: *
Maximum age (seconds): 86400
  1. 测试

这就是我使用当前库对我有用的方法(另请注意 Jim Xu 对最新库的解决方案的回答)

async uploadFileToAzure(file, filename, index){
    
        
    this.AStorage.getSAS(this.token, {"filename":filename}).subscribe(async sas=>{
      var self = this;
      this.sas = sas;
      var blobUri = 'https://xxxx.blob.core.windows.net/'; //actual blobUri goes here
      var blobService = AzureStorage.Blob.createBlobServiceWithSas(blobUri, this.sas["token"]);
      var customBlockSize = file.size > 1024 * 1024 * 32 ? 1024 * 1024 * 4 : 1024 * 512; 
      blobService.singleBlobPutThresholdInBytes = customBlockSize;
  
      var finishedOrError = false;
      var self = this;
      var speedSummary = blobService.createBlockBlobFromBrowserFile('input-data', filename, file, {blockSize : customBlockSize}, function(error, result, response) {
        finishedOrError = true;
        if (error) {
            // Upload blob failed
            self.show_toast('Problema: Volver a intentar o contactar al administrador');
        } else {
            // Upload successfully
            self.show_toast('Subida Exitosa');
            finish_upload();

            return result;
        }
      });
      
      speedSummary.on('progress', function () {
        var process = speedSummary.getCompletePercent();
        displayProcess(process);
      })

      var finish_upload = function(){
        //TODO: set upload finish process
        
      }

      var file_to_process = this.files_to_process[index]
      var displayProcess = function(process){
        console.log('file_to_process', file_to_process)
        var s = document.getElementById(file_to_process)
        s.innerHTML = process;
        //var s = document.getElementById(progress_bars[index])
      }  
    });    
  }