【问题标题】:Adding File to Azure Storage Blob from Angular从 Angular 将文件添加到 Azure 存储 Blob
【发布时间】:2020-06-17 09:00:47
【问题描述】:

我正在尝试弄清楚如何使用 ngx-awesome-uploader 将图像从 Angular 上传到 azure 存储 blob。

我希望能够使用此库将其从 Angular 直接发送到 azure storage blob。我已经能够将它发送到我的 nodejs 后端没有问题,但是将它直接发送到 blob 存储对我来说是一个挑战。谁能提供一个如何做到这一点的工作示例?感谢您的帮助!

Choose Simple Demo in stackblitz. Not Advanced Demo

Stackblitz example of ngx awesome uploader

文件被传递给这个。 (代码下方的控制台输出)

import { FilePreviewModel } from 'ngx-awesome-uploader';
import { HttpRequest, HttpClient, HttpEvent, HttpEventType } from '@angular/common/http';
import { map } from 'rxjs/operators';
import { Observable } from 'rxjs';
import { FilePickerAdapter } from 'ngx-awesome-uploader';

export class DemoFilePickerAdapter extends FilePickerAdapter {
  constructor(private http: HttpClient) {
    super();
  }
  public uploadFile(fileItem: FilePreviewModel) {
    const form = new FormData();
    form.append('file', fileItem.file);

   console.log("FILE OUTPUT");
    console.log(fileItem.file);


//need to replace everything below with code to add to storage blob

    const api = 'https://demo-file-uploader.free.beeceptor.com';
    const req = new HttpRequest('POST', api, form, {reportProgress: true});
    return this.http.request(req)
    .pipe(
      map( (res: HttpEvent<any>) => {
          if (res.type === HttpEventType.Response) {
          return res.body.id.toString();
        } else if (res.type ===  HttpEventType.UploadProgress) {
            // Compute and show the % done:
            const UploadProgress = +Math.round((100 * res.loaded) / res.total);
            return UploadProgress;
        }
      })
      );
  }

}

FILE OUTPUT 的 console.output 是

【问题讨论】:

  • 这段代码 sn-p 让我很困惑。你能给我看一个我链接的 stackblitz 的例子吗?
  • @user6680 - 请编辑您的问题以包含任何/所有相关代码,而不是要求人们点击链接。不鼓励链接到代码,因为链接可能会腐烂/死亡/消失,因此未来的读者没有参考。在您的问题中包含所有细节非常重要,包括您遇到问题的领域、错误、预期结果与实际结果等。
  • 很抱歉。我在我的问题中添加了其他信息

标签: javascript angular azure azure-storage azure-blob-storage


【解决方案1】:

根据我的测试,如果要上传文件到Azure blob,请参考以下步骤

  1. 安装 Azure 存储 SDK
npm install @azure/storage-blob
  1. 更新 app.component.html 文件
<div class="form-group">
  <label for="file">Choose File</label>
  <input type="file"
         id="file"
         (change)="onFileChange($event)">
</div>


  1. 更新 Environment.ts
export const environment = {
  production: false,
  accountName : "<account name>",
  containerName:"",
   key:""
};
  1. 在 polyfills.ts 中添加以下代码
(window as any).global = window;
(window as any).process = require( 'process' );
(window as any).Buffer = require( 'buffer' ).Buffer;
  1. 在 app.component.ts 中添加如下代码
import { Component } from '@angular/core';
import {BlobServiceClient,AnonymousCredential,newPipeline } from '@azure/storage-blob';
import { environment } from './../environments/environment';
@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];
   console.log(this.currentFile.name)
    console.log(this.currentFile.type)
// generate account sas token
  const accountName =environment.accountName;
  const key=environment.key;
  const start = new Date(new Date().getTime() - (15 * 60 * 1000));
  const end = new Date(new Date().getTime() + (30 * 60 * 1000));
const signedpermissions = 'rwdlac';
  const signedservice = 'b';
  const signedresourcetype = 'sco';
  const signedexpiry = end.toISOString().substring(0, end.toISOString().lastIndexOf('.')) + 'Z';
  const signedProtocol = 'https';
  const signedversion = '2018-03-28';

  const StringToSign =
      accountName+ '\n' +
      signedpermissions + '\n' +
      signedservice + '\n' +
      signedresourcetype + '\n' +
       '\n' +
      signedexpiry + '\n' +
       '\n' +
      signedProtocol + '\n' +
signedversion + '\n';
  const crypto =require('crypto')
   const sig = crypto.createHmac('sha256', Buffer.from(key, 'base64')).update(StringToSign, 'utf8').digest('base64');
  const sasToken =`sv=${(signedversion)}&ss=${(signedservice)}&srt=${(signedresourcetype)}&sp=${(signedpermissions)}&se=${encodeURIComponent(signedexpiry)}&spr=${(signedProtocol)}&sig=${encodeURIComponent(sig)}`;
  const containerName=environment.containerName;
  
            const pipeline =newPipeline (new AnonymousCredential(),{
            retryOptions: { maxTries: 4 }, // Retry options
            userAgentOptions: { userAgentPrefix: "AdvancedSample V1.0.0" }, // Customized telemetry string
            keepAliveOptions: {
                // Keep alive is enabled by default, disable keep alive by setting false
                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)
           const response = await client.uploadBrowserData(this.currentFile,{
                  blockSize: 4 * 1024 * 1024, // 4MB block size
                  concurrency: 20, // 20 concurrency
                  onProgress: (ev) => console.log(ev),
                  blobHTTPHeaders :{blobContentType:this.currentFile.type}
                  })
    console.log(response._response.status)
 }
}

  1. Configure CORS for Azure storage
Allowed origins: *
Allowed verbs: DELETE,GET,HEAD,MERGE,POST,OPTIONS,PUT
Allowed headers: *
Exposed headers: *
Maximum age (seconds): 86400
  1. 测试。我上传一个pdf文件

关于如何配置CORS,请参考以下步骤

  1. 登录Azure Portal

  2. 选择您使用的 Azure 帐户

  3. 配置 CORS


更新

如果你不能使用函数createHmac,你可以尝试使用crypto-js。详细步骤如下

  1. 安装 SDK
npm install crypto-js --save
npm install @types/crypto-js --save-dev
  1. 更新 app.component.ts 中的代码
...
import * as CryptoJS from 'crypto-js';


...
export class AppComponent {
  title = 'web1';
  currentFile : File =null;
  onFileChange(event) {
    this.currentFile = event.target.files[0];
   console.log(this.currentFile.name)
    console.log(this.currentFile.type)
// generate account sas token
  const accountName =environment.accountName;
  const key=environment.key;
  const start = new Date(new Date().getTime() - (15 * 60 * 1000));
  const end = new Date(new Date().getTime() + (30 * 60 * 1000));
const signedpermissions = 'rwdlac';
  const signedservice = 'b';
  const signedresourcetype = 'sco';
  const signedexpiry = end.toISOString().substring(0, end.toISOString().lastIndexOf('.')) + 'Z';
  const signedProtocol = 'https';
  const signedversion = '2018-03-28';

  const StringToSign =
      accountName+ '\n' +
      signedpermissions + '\n' +
      signedservice + '\n' +
      signedresourcetype + '\n' +
       '\n' +
      signedexpiry + '\n' +
       '\n' +
      signedProtocol + '\n' +
signedversion + '\n';

 var str =CryptoJS.HmacSHA256(StringToSign,CryptoJS.enc.Base64.parse(key));
 var sig = CryptoJS.enc.Base64.stringify(str);
 
 
  const sasToken =`sv=${(signedversion)}&ss=${(signedservice)}&srt=${(signedresourcetype)}&sp=${(signedpermissions)}&se=${encodeURIComponent(signedexpiry)}&spr=${(signedProtocol)}&sig=${encodeURIComponent(sig)}`;
  const containerName=environment.containerName;

            const pipeline =newPipeline (new AnonymousCredential(),{
            retryOptions: { maxTries: 4 }, // Retry options
            userAgentOptions: { userAgentPrefix: "AdvancedSample V1.0.0" }, // Customized telemetry string
            keepAliveOptions: {
                // Keep alive is enabled by default, disable keep alive by setting false
                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)
           const response = await client.uploadBrowserData(this.currentFile,{
                  blockSize: 4 * 1024 * 1024, // 4MB block size
                  concurrency: 20, // 20 concurrency
                  onProgress: (ev) => console.log(ev),
                  blobHTTPHeaders :{blobContentType:this.currentFile.type}
                  })
    console.log(response._response.status)
 }
}

【讨论】:

  • 我已经集成了你的代码,并且由于它的设计方式,我已经摆脱了 ngx-awesome-uploader。摆脱这个库让我处理文件变得更容易了。我现在使用不同的图像上传器/裁剪器,当我点击确认图像时,它将图像存储为 base64 类型。我已经添加了您的代码,但出现了 CORS 错误。我知道你在回答中提到了 CORS,但我不明白我应该在哪里添加有角的 CORS。 Reason: CORS header ‘Access-Control-Allow-Origin’ missing)
  • 有道理。感谢您的澄清。我还有一个我一直在尝试解决的问题。 CORS 一开始是问题,但现在它说crypto.createHmac is not a function 不知道你可以引用nodejs 模块const crypto = require('crypto') 我尝试安装npm i crypto --save,但里面唯一的东西是一个package.json 文件和自述文件。 package.json 文件:pastebin.com/xrXPeFTe 我试过这个:stackoverflow.com/a/43353846/4350389,但即使它识别功能,它也会给我同样的错误:postimg.cc/zytTWn97 有什么想法吗?
  • @user6680 你能告诉我你的角度版本吗?
  • 它是 Angular:8.2.8
  • @user6680 可以试试import {createHmac} from 'crypto'吗?
猜你喜欢
  • 2017-08-18
  • 2021-04-30
  • 2020-08-18
  • 2021-07-29
  • 2020-08-25
  • 2013-02-06
  • 2021-03-07
  • 2020-11-11
  • 2019-05-15
相关资源
最近更新 更多