使用 Angular 和 Multer 上传多个文件

Uploading multiple files with Angular and Multer

我需要帮助来了解如何使用 Angular 7 处理 multer (nodeJS)。 我尝试了很多不同的情况,但似乎无法上传任何文件...... 我的文件来自 ReactiveForm:

<mat-tab
        label="Documents"
        formGroupName="docs">
          <mat-list>
              <mat-nav-list>
                <a mat-list-item
                (click)="fsPicker.click()">
                Upload financial statements
                </a><input type="file" #fsPicker (change)="onDocPicked($event, 'fs')">

                <a mat-list-item
                (click)="cdPicker.click()">
                Upload the constitutional documents
                </a><input type="file" #cdPicker (change)="onDocPicked($event, 'cd')">

                <a mat-list-item
                (click)="idPicker.click()">
                Upload the ID
                </a><input type="file" #idPicker (change)="onDocPicked($event, 'id')">

                <a mat-list-item
                (click)="adPicker.click()">
                Upload the bank account details
                </a><input type="file" #adPicker (change)="onDocPicked($event, 'ad')">

              </mat-nav-list>
          </mat-list>
        </mat-tab>

由 MimeValidator 控制:

// INSIDE NGONINIT: 
    this.customerForm = new FormGroup({
          info: new FormGroup({
            name: new FormControl(null, {validators: Validators.required}),
            vat: new FormControl(null, {validators: Validators.required}),
          }),
          docs: new FormGroup({
            fs: new FormControl(null, {asyncValidators: mimeType}),
            cd: new FormControl(null, {asyncValidators: mimeType}),
            id: new FormControl(null, {asyncValidators: mimeType}),
            ad: new FormControl(null, {asyncValidators: mimeType})
          })
        });

// IN THE REST OF THE CLASS

  onDocPicked(event: Event, type: string) {
    const file = (event.target as HTMLInputElement).files[0];
    this.customerForm.get('docs').patchValue({
      [type]: file
    });
    this.customerForm.get('docs').get(type).updateValueAndValidity();
    this.customerForm.get('docs').get(type).markAsDirty();
    setTimeout(() => {
      if (!this.customerForm.get('docs').get(type).valid) {
      this.openAlert();
      this.customerForm.get('docs').patchValue({
          [type]: null
        });
      }
    }, 100);
  }

然后提交并发送到专属服务:

onSubmit() {
    if (!this.customerForm.valid) {
      return;
    }
    this.isLoading = true;
    if (!this.editMode) {

      this.customerService.addCustomer(this.customerForm.get('info').value, this.customerForm.get('docs').value);
      this.customerForm.reset();
    } else {
      const updatedCustomer: Customer = {
        id: this.id,
        name: this.customerForm.get('info').value.name,
        vat: this.customerForm.get('info').value.vat
      };
      this.customerService.updateCustomer(this.id, updatedCustomer);
    }
    this.router.navigate(['/customers']);
  }

在服务内部,处理并发送到后端:

addCustomer(info, docsData) {
    const customerData = new FormData();
    customerData.append('name', info.name);
    customerData.append('vat', info.vat);
    customerData.append('docs', docsData);
    console.log(docsData);
    this.http.post<{message: string, customerId: string}>(
      'http://localhost:3000/api/customers',
      customerData
      )
      .subscribe((res) => {
        const customer: Customer = {
          id: res.customerId,
          name: info.name,
          vat: info.vat
        };
        this.customers.push(customer);
        this.customersUpdated.next([...this.customers]);
      });
  }

最后但并非最不重要的由快递和 multer 接收和处理:

  const storage = multer.diskStorage({
  destination: (req, file, cb) => {
    const isValid = MIME_TYPE_MAP[file.mimetype];
    let err = new Error('invalid mime type!');
    if (isValid) {
      err = null;
    }
    cb(err, 'backend/docs');
  },
  filename: (req, file, cb) => {
    const name = file.originalname.toLowerCase().split('').join('-');
    const ext = MIME_TYPE_MAP[file.mimetype];
    cb(null, name + '-' + Date.now() + '.' + ext);
  }
});

const upload = multer({storage: storage});

router.post('', upload.any(),
// .fields([
//   {name: 'fs'},
//   {name: 'cd'},
//   {name: 'id'},
//   {name: 'ad'},
//   ]),
  (req, res, next) => {
  const customer = new Customer({
    name: req.body.name,
    vat: req.body.vat,
  });
  customer.save().then(result => {
    res.status(201).json({
      message: 'Customer added successfully!',
      customerId: result.id
    });
  });
});

我认为问题出在我试图发送到服务器的对象...但我不确定如何正确处理这个问题。 即使通过调用 multer 的 any 命令,也不会保存任何内容。

这是 stackblitz 上完整项目的 link:

https://stackblitz.com/github/ardzii/test

我发送的数据类型错误。为了更正(现在似乎可以工作),我必须在附加文件的 FormData 中精确:

const customerData = new FormData();
    customerData.append('name', info.name);
    customerData.append('vat', info.vat);
    customerData.append('fs', docsData.fs as File, info.vat + 'fs');
    customerData.append('cd', docsData.cd as File, info.vat + 'cd');
    customerData.append('id', docsData.id as File, info.vat + 'id');
    customerData.append('ad', docsData.ad as File, info.vat + 'ad');

完成后,我可以通过调用以下命令轻松地使用 multer 处理文件:

upload.
fields([
  {name: 'fs', maxCount: 1},
  {name: 'cd', maxCount: 1},
  {name: 'id', maxCount: 1},
  {name: 'ad', maxCount: 1},
  ]),

upload 变量是带有参数的 multer 实例(见问题)。