【问题标题】:Angular 6 post-request with a multipart form doesn't include the attached file of the object posted具有多部分表单的 Angular 6 后请求不包括发布的对象的附件
【发布时间】:2018-11-07 09:37:39
【问题描述】:

我正在尝试通过 Angular 6 将表单与文件一起发送到我的 API,但帖子不包含该文件,即使应该发送的对象包含该文件。

当我查看控制台日志时,我看到了预期的内容,金额:“金额”,发票文件:文件...。 但在传出请求中,该字段显示 invoicefile:{},现在另一端收到文件。最后附上一些图片。

最后,我的 API 告诉我所有字段都丢失了,但我认为这是另一个问题。

组件如下所示:

import { Component, OnInit } from '@angular/core';
import { Router } from '@angular/router';
import { first } from 'rxjs/operators';
import { FormGroup, FormBuilder, FormControl, Validators, FormArray, ReactiveFormsModule } from '@angular/forms';
import { HttpClient } from '@angular/common/http';

import { AlertService } from '../_services';
import { InvoiceService } from '../_services';
import { Invoice } from '../_models';

@Component({
  selector: 'app-registerinvoice',
  templateUrl: './registerinvoice.component.html',
  styleUrls: ['./registerinvoice.component.css']
})
export class RegisterinvoiceComponent implements OnInit {
  public registerForm: FormGroup;
  public submitted: boolean;

  constructor(
    private router: Router,
    private invoiceService: InvoiceService,
    private alertService: AlertService,
    private http: HttpClient,

  ) { }
  fileToUpload: File = null;

  ngOnInit() {
    this.registerForm = new FormGroup({
      serial: new FormControl('', [<any>Validators.required, <any>Validators.minLength(5)]),
      amount: new FormControl('', [<any>Validators.required, <any>Validators.minLength(4)]),
      debtor: new FormControl('', [<any>Validators.required, <any>Validators.minLength(10)]),
      dateout: new FormControl('', [<any>Validators.required, <any>Validators.minLength(8)]),
      expiration: new FormControl('', [<any>Validators.required, <any>Validators.minLength(8)]),
    });
  }
  handleFileInput(files: FileList){
    this.fileToUpload=files.item(0);
  }

  deliverForm(invoice: Invoice, isValid) {
    this.submitted=true;
    if (!isValid){
      return;
    }
    invoice.invoicefile=this.fileToUpload;
    console.log(invoice);
    console.log(typeof(invoice.invoicefile));
    this.invoiceService.create(invoice)
      .pipe(first())
      .subscribe(
        data => {
          this.alertService.success('Invoice successfully uploaded', true);
          this.router.navigate(['/profile']);
        },
        error => {
          this.alertService.error(error);
        });
  }

}

随后是提供帖子的服务:

import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Http } from '@angular/http';
import { Invoice } from '../_models';
import { FormGroup } from '@angular/forms';

const HttpUploadOptions = {
  headers: new HttpHeaders({ "Content-Type": "multipart/form-data" })
}
@Injectable({
  providedIn: 'root'
})
export class InvoiceService {

  constructor(
    private http: HttpClient
  ) { }
  create(invoice: Invoice){
    return this.http.post('/api/v1/invoices/', invoice, HttpUploadOptions)
  }
}

最后是班级:

export class Invoice {
    id: any;
    serial: any;
    amount: any;
    debtor: any;
    dateout: any;
    expiration: any;
    fid: any;
    invoicefile: File;
}

看起来正确的控制台日志:

以及文件丢失的传出请求:

编辑:

现在创建的服务代码如下所示:

create(invoice: Invoice){
    let payload=new FormData();
    payload.append('amount', invoice.amount);
    payload.append('debtor', invoice.debtor);
    payload.append('serial', invoice.serial);
    payload.append('dateout', invoice.dateout);
    payload.append('expiration', invoice.expiration);
    payload.append('invoicefile', invoice.invoicefile);
    return this.http.post('/api/v1/invoices/', payload, HttpUploadOptions)
  }

响应看起来像这样。对我来说看起来很奇怪,而且我的后端仍然有一些错误,但这是另一个问题。

【问题讨论】:

  • 这是 JSON,我认为不是多部分,尽管有标题
  • 对如何解决这个问题有任何想法吗?
  • 什么问题?
  • 分享服务器端脚本以了解验证是如何进行的

标签: angular file typescript post file-upload


【解决方案1】:

您的 POST 请求正文实际上是 JSON,而不是您希望的 Multipart(尽管 Content-Type 标头说什么)。

为了解决这个问题,您需要构建一个 FormData 对象,并在您的请求中使用它:

let input = new FormData();
// Add your values in here
input.append('id', invoice.id);
input.append('invoiceFile', invoice.invoiceFile);
// etc, etc

this.http.post('/api/v1/invoices/', input, HttpUploadOptions)

【讨论】:

  • 我按照您的描述编辑了我的代码,多部分响应应该是这样的吗?我想弄清楚问题是否肯定出在我的后端。因为它说所有字段都丢失了,但是,如果该响应是正确的,那是另一个问题。
  • 是的,这样更好,现在是正确的格式。只需确保您的后端也设置为期望多部分
  • 为简洁起见,我将包括为使其正常工作 HttpUploadOptions 需要完全删除。如果它被强制为 multipart/form-data 至关重要的 WebKitFormBoundary 不包括在内,它需要包含在标题中,否则后端不知道在哪里剪切不同的表单输入,并且会抛出一个错误。
  • 谢谢哥们,它对我有很大帮助。
【解决方案2】:

从标题中删除 multipart/form-data 以解决此问题

const HttpUploadOptions = {
  headers: new HttpHeaders({ "Content-Type": "multipart/form-data" })
}

解决方案

const HttpUploadOptions = {
  headers: new HttpHeaders({ "Accept": "application/json" })
}

【讨论】:

  • 这个对我有用。 Angular 6 将文件作为二进制而不是表单数据提交。
  • 谢谢哥们,它对我有很大帮助。
  • 你让我开心..谢谢
  • 这在 Angular 12 上为我工作,并在 WordPress 中发送了一封包含 Contact Form 7 API REST 的电子邮件
【解决方案3】:

我之前有这个出错了

const formData = new FormData();
formData.append(...);
this.http.post(apiUrl, {formData});

我刚刚从大括号中删除了对象,它起作用了

this.http.post(apiUrl, formData);

【讨论】:

  • 还注意到,我在模板中有单个输入元素,甚至没有表单标签,并且像魅力一样工作
【解决方案4】:

伙计们,

如果您的选项用完了。您也可以尝试将内容类型作为空字符串传递,如下所示:

const HttpUploadOptions = {
  headers: new HttpHeaders({ 'Content-Type':'' })
}

const HttpUploadOptions = {
  headers: new HttpHeaders().append({ 'Content-Type':'' });
}

【讨论】:

    【解决方案5】:

    对于 Angular v8+,你可以试试 @ng-stack/forms,它有 "file" support 和验证功能。

    你甚至不需要添加标题,只需传递表单值:

    // Value of formControl here is instance of FormData
    // and it's OK to directly upload this value.
    const formData = this.formControl.value;
    
    this.httpClient.post('api/path', formData).subscribe(() => {
      // Do something
    });
    

    【讨论】:

      猜你喜欢
      • 2020-01-20
      • 2021-03-23
      • 2016-11-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-23
      • 2014-05-10
      相关资源
      最近更新 更多