javascript - Cloud Storage for Firebase 限制(组合)多个文件上传的大小

标签 javascript angular firebase google-cloud-storage firebase-storage

在我的 Angular 应用程序中,我有一个带有文件上传输入的联系表单。如果组合文件超过 20 MB,前端的文件上传输入将不允许发送联系表单。 有什么方法可以在 Cloud Storage for Firebase 中实现相同的逻辑吗?目前我只能限制 20 MB,但对于每个文件,即如果有人上传 10 个文件,每 19 MB 他/她将无法发送表单,但文件将发送到我的无服务器后端,这是我不想要的。

contact.component.html

<mat-form-field>
  <!--
    Accept only files in the following format: .doc, .docx, .jpg, .jpeg, .pdf, .png, .xls, .xlsx. However, this is easy to bypass, Cloud Storage rules has been set up on the back-end side.
  -->
  <ngx-mat-file-input
    [accept]="[
      '.doc',
      '.docx',
      '.jpg',
      '.jpeg',
      '.pdf',
      '.png',
      '.xls',
      '.xlsx'
    ]"
    (change)="uploadFile($event)"
    formControlName="fileUploader"
    multiple
    aria-label="Here you can add additional files about your project, which can be helpeful for us."
    placeholder="Additional files"
    title="Additional files"
    type="file"
  >
  </ngx-mat-file-input>
  <mat-icon matSuffix>folder</mat-icon>
  <mat-hint
    >Accepted formats: DOC, DOCX, JPG, JPEG, PDF, PNG, XLS and XLSX,
    maximum files upload size: 20 MB.
  </mat-hint>
  <!--
    Non-null assertion operators are required to let know the compiler that this value is not empty and exists.
  -->
  <mat-error
    *ngIf="contactForm.get('fileUploader')!.hasError('maxContentSize')"
  >
    This size is too large,
    <strong
      >maximum acceptable upload size is
      {{
        contactForm.get('fileUploader')?.getError('maxContentSize')
          .maxSize | byteFormat
      }}</strong
    >
    (uploaded size:
    {{
      contactForm.get('fileUploader')?.getError('maxContentSize')
        .actualSize | byteFormat
    }}).
  </mat-error>
</mat-form-field>

contact.component.ts(尺寸验证器)

public maxFileSize = 20971520;
public contactForm: FormGroup = this.formBuilder.group({
    fileUploader: [
      '',
      Validators.compose([
        FileValidator.maxContentSize(this.maxFileSize),
        Validators.maxLength(512),
        Validators.minLength(2)
      ])
    ].toString()
})

contact.component.ts(文件 uploader )

/**
   * @description Upload additional files to Cloud Firestore and get URL to the files.
   * @param {event} - object of sent files.
   * @returns {void}
   */
  public uploadFile(event: any): void {
    // Iterate through all uploaded files.
    for (let i = 0; i < event.target.files.length; i++) {
      const randomId = Math.random()
        .toString(36)
        .substring(2); // Create random ID, so the same file names can be uploaded to Cloud Firestore.

      const file = event.target.files[i]; // Get each uploaded file.

      // Get file reference.
      const fileRef: AngularFireStorageReference = this.angularFireStorage.ref(
        randomId
      );

      // Create upload task.
      const task: AngularFireUploadTask = this.angularFireStorage.upload(
        randomId,
        file
      );

      // Upload file to Cloud Firestore.
      task
        .snapshotChanges()
        .pipe(
          finalize(() => {
            fileRef.getDownloadURL().subscribe((downloadURL: string) => {
              this.angularFirestore
                .collection(process.env.FIRESTORE_COLLECTION_FILES!) // Non-null assertion operator is required to let know the compiler that this value is not empty and exists.
                .add({ downloadURL: downloadURL });
              this.downloadURL.push(downloadURL);
            });
          }),
          catchError((error: any) => {
            return throwError(error);
          })
        )
        .subscribe();
    }
  }

存储.规则

rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
        allow read; // Required in order to send this as attachment.
      // Allow write files Firebase Storage, only if:
      // 1) File is no more than 20MB
      // 2) Content type is in one of the following formats: .doc, .docx, .jpg, .jpeg, .pdf, .png, .xls, .xlsx.
      allow write: if request.resource.size <= 20 * 1024 * 1024
        && (request.resource.contentType.matches('application/msword')
        || request.resource.contentType.matches('application/vnd.openxmlformats-officedocument.wordprocessingml.document')
        || request.resource.contentType.matches('image/jpg')
        || request.resource.contentType.matches('image/jpeg')
        || request.resource.contentType.matches('application/pdf')
                || request.resource.contentType.matches('image/png')
        || request.resource.contentType.matches('application/vnd.ms-excel')
        || request.resource.contentType.matches('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'))
    }
  }
}

最佳答案

Cloud Storage for Firebase 安全规则的限制分别适用于每个文件/对象,不适用于整个操作。在云存储规则的上下文中,这种类型的限制也没有什么意义,因为用户可以启动另一个操作来上传其他文件。

需要考虑的一些选项:

  1. 如果您对用户上传的文件的名称进行硬编码(这也意味着您将限制他们可以上传的文件数量),并为每个特定用户的文件创建一个文件夹,您可以确定用户文件夹中所有文件的总和,从而以这种方式限制总和。

  2. 或者,您可以在客户端上将所有文件压缩在一起,然后上传生成的存档。在这种情况下,安全规则可以强制规定该文件的最大大小。

  3. 当然,您可以包含客户端 JavaScript 代码来检查这两种情况下组合文件的最大大小。恶意用户可以轻松绕过此 JavaScript,但大多数用户都不是恶意的,他们会感谢您通过阻止无论如何都会被拒绝的上传来节省他们的带宽。

  4. 您还可以使用 HTTPS 云函数作为上传目标,然后仅在文件满足您的要求时将文件传递到云存储。

  5. 或者,您可以使用云函数,该函数在用户上传时触发,并在更改后验证该用户的文件。届时您可以纠正这种情况。

许多这样的场景要求(或者更好地工作)您有一个结构,您可以从该结构中看到用户上传每个文件的路径。请参阅 user-private files 上的文档有关此结构的更多信息。

关于javascript - Cloud Storage for Firebase 限制(组合)多个文件上传的大小,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57539021/

相关文章:

javascript - 从没有页面刷新的模式异步 Ajax 保存 Laravel 5.2

javascript - 如何根据 Electron 菜单点击更改 Redux 状态?

c# - ASP.net core signalr Angular 客户端,错误 "Response to preflight request doesn' t 通过访问控制检查”

asp.net - Angular 4 : Can't bind to 'ngModel' since it isn't a known property of 'input'

android - 如何通过 REST api 使用 SMS for Firebase 执行 2FA?

node.js - 找不到模块 'firebase-admin'

javascript - 返回包含对象数组中特定参数的随机对象

javascript - Angular 参数不是函数,未定义

angular - 保护多个 Angular 2 组件的好方法

firebase - 为什么 firebase 电子邮件链接在 URL 中包含 apiKey?