【问题标题】:429 Too Many Requests - Angular 7 - on multiple file upload429 Too Many Requests - Angular 7 - 多个文件上传
【发布时间】:2020-02-06 14:21:41
【问题描述】:

当我尝试同时上传超过几百个文件时,我遇到了这个问题。

API 接口仅适用于一个文件,因此我必须调用发送每个文件的服务。现在我有这个:

onFilePaymentSelect(event): void {
    if (event.target.files.length > 0) {
      this.paymentFiles = event.target.files[0];
    }
    let i = 0;
    let save = 0;
    const numFiles = event.target.files.length;
    let procesed = 0;
    if (event.target.files.length > 0) {
      while (event.target.files[i]) {
      const formData = new FormData();
      formData.append('file', event.target.files[i]);
      this.payrollsService.sendFilesPaymentName(formData).subscribe(
      (response) => {
        let added = null;
        procesed++;
        if (response.status_message === 'File saved') {
          added = true;
          save++;
        } else {
          added = false;
        }
        this.payList.push({ filename, message, added });
      });
    i++;
  }
}

因此,我确实有一段时间将每个文件发送到 API,但我在大量文件上收到消息“429 太多请求”。有什么办法可以改进吗?

【问题讨论】:

  • 您可以使用interval 来调整请求的速度。
  • 给我一点时间,我会做一个stackblitz,因为解释起来更难

标签: javascript angular typescript angular7 http-status-code-429


【解决方案1】:

使用可观察对象将使该任务更容易推理(而不是使用命令式编程)。

浏览器通常允许您并行发出 6 个请求,并将其他请求排队。但是我们不希望浏览器为我们管理该队列(或者如果我们在节点环境中运行,我们就不会拥有它)。

我们想要什么:我们想要上传很多文件。它们应该通过始终并行运行 5 个请求来尽可能高效地排队和上传。 (因此我们为应用中的其他请求保留 1 个免费)。

为了演示,让我们先构建一些模拟:

function randomInteger(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

const mockPayrollsService = {
  sendFilesPaymentName: (file: File) => {
    return of(file).pipe(
      // simulate a 500ms to 1.5s network latency from the server
      delay(randomInteger(500, 1500))
    );
  }
};

// array containing 50 files which are mocked
const files: File[] = Array.from({ length: 50 })
  .fill(null)
  .map(() => new File([], ""));

我认为上面的代码是不言自明的。我们正在生成模拟,因此我们可以看到代码的核心将如何实际运行,而无需真正访问您的应用程序。

现在,主要部分:

const NUMBER_OF_PARALLEL_CALLS = 5;

const onFilePaymentSelect = (files: File[]) => {
  const uploadQueue$ = from(files).pipe(
    map(file => mockPayrollsService.sendFilesPaymentName(file)),
    mergeAll(NUMBER_OF_PARALLEL_CALLS)
  );

  uploadQueue$
    .pipe(
      scan(nbUploadedFiles => nbUploadedFiles + 1, 0),
      tap(nbUploadedFiles =>
        console.log(`${nbUploadedFiles}/${files.length} file(s) uploaded`)
      ),
      tap({ complete: () => console.log("All files have been uploaded") })
    )
    .subscribe();
};

onFilePaymentSelect(files);
  • 我们使用from将文件一一发送到可观察对象中
  • 使用map,我们准备了对 1 个文件的请求(但由于我们没有订阅它并且 observable 是冷的,所以请求只是准备好了,没有触发!)
  • 我们现在使用mergeMap 来运行一个调用池。由于mergeMap 将并发作为参数,我们可以说“请同时运行最多 5 个调用”
  • 然后我们将scan 仅用于显示目的(用于统计已成功上传的文件数)

这是一个现场演示:https://stackblitz.com/edit/rxjs-zuwy33?file=index.ts

打开控制台看看我们不是一次上传所有的

【讨论】:

    猜你喜欢
    • 2021-12-31
    • 1970-01-01
    • 1970-01-01
    • 2021-12-13
    • 2020-12-23
    • 2021-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多