首页 > 解决方案 > 发布 POST 请求时,Angular 中的文件上传会出错

问题描述

我有一个这样的 HTML 表单,可以将文件从前端上传到后端并执行一些操作:

<button mat-raised-button color="primary" type="button" style='margin-right:20px' (click)="selectFile()">Select File To Upload</button> 
<input #fileUploadInput type="file" id="fileUpload" hidden name="avatar" (change)="fileChangeEvent($event)">
<button mat-raised-button color="primary" type="button" style='margin-right:20px' enctype="multipart/form-data" (click)="uploadFile()">Submit</button>
        
<br><br>
<a class="generate-full-width" style="color: darkred;" *ngIf="fileName"><strong>{{fileName}}</strong></a>

component.ts 是:

export class uploadFileDialog {

  constructor(
    public dialogRef: MatDialogRef<AddProductDialog>,
    private uploadService: UploadService,
    private builder: FormBuilder, public dialog: MatDialog,
    @Inject(MAT_DIALOG_DATA) public data) {
  }

  @ViewChild('fileUploadInput', {static: false})
  fileUploadVariable: ElementRef;
  fileName;
  currentFile: File;
  filesToUpload = [];

  resetFile(){
    this.fileUploadVariable.nativeElement.value = "";
  }

  
  selectFile(){
    this.resetFile();
    let el: HTMLElement = this.fileUploadVariable.nativeElement as HTMLElement;
    el.click();
  }

  fileChangeEvent(fileInput: any) {
    let file = fileInput.target.files[0]
    console.log(file)
    //console.log(file.data.toString());
    this.filesToUpload = [];
    this.filesToUpload.push(file);
    this.fileName = file['name'];
  }

  uploadFile(){
    this.currentFile = this.fileName;
    console.log(this.currentFile);
    this.uploadService.uploadFile(this.currentFile)
      .subscribe((data) => {
        
        console.log(data)
      },
      error => {
        console.log(error)
      });
  }
}

Service.ts 是:

uploadFile(file: File): Observable<any> {

    let headers = new HttpHeaders({
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      //'Access-Control-Allow-Headers': 'X-Requested-With, content-type, Authorization'
      'Access-Control-Allow-Headers': 'Content-Type,Accept,X-Access-Token,X-Key,Authorization,X-Requested-With,Origin,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,content-type=multipart/*'
    })

    let options = {headers:headers, observer: 'response'};

    const formData: FormData = new FormData();

    formData.append('file', file);

    //return this.http.post(this.url+'/fileUpload/upload', formData,options)
    const req = new HttpRequest('POST', this.url+'/fileUpload/upload', formData, {
      reportProgress: true,
      responseType: 'json'
    });

    return this.http.request(req);
  }

Java后端的控制器文件是:

@RestController
@CrossOrigin(origins = "*", allowedHeaders="*", exposedHeaders="Access-Control-Allow-Origin")
@RequestMapping("/fileUpload")

public class FileController {
    
    private final FileService fileService;
     
    @Autowired
    public FileController(FileService fileService) {
        this.fileService = fileService;
    }
 
    @PostMapping(value = "/upload")
    public void handleFileUpload(@RequestParam("file") MultipartFile file) throws IOException {
        fileService.storeFile(file);
    }}

Java后端的服务文件是:

@Service
public class FileService {

    private static final String FILE_DIRECTORY = "D:\\temp";
     
    public void storeFile(MultipartFile file) throws IOException {
        Path filePath = Paths.get(FILE_DIRECTORY + "\" + file.getOriginalFilename());
 
        Files.copy(file.getInputStream(), filePath, StandardCopyOption.REPLACE_EXISTING);
    }
    
}

在控制台中上传时,我可以看到文件名。此外,在请求的正文中,formData 将 xml 文件显示为 Networks 选项卡中的内容。我的 Java 控制台,我收到错误:

2020-12-15 12:26:53.144  WARN 9688 --- [nio-8080-exec-8] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.web.multipart.support.MissingServletRequestPartException: Required request part 'file' is not present]

前端控制台中的错误:

HttpHeaderResponse {headers: HttpHeaders, status: 400, statusText: "OK", url: "http://localhost:8080/fileUpload/upload", ok: false, …}
headers: HttpHeaders {normalizedNames: Map(0), lazyUpdate: null, lazyInit: ƒ}
ok: false
status: 400
statusText: "OK"
type: 2
url: "http://localhost:8080/fileUpload/upload"
__proto__: HttpResponseBase

我究竟做错了什么?

标签: javahtmlangularspring-bootfile-upload

解决方案


您只发送文件名,而不是实际的文件 blob。

尝试进行以下更改,

组件.ts:

  uploadFile() {
    this.currentFile = this.fileName;
    console.log(this.currentFile, this.filesToUpload[0]);
    this.uploadService.uploadFile(this.currentFile, this.filesToUpload[0])
      .subscribe((data) => {
        console.log(data)
      },
      error => {
        console.log(error)
   });
  }

服务.ts

uploadFile(fileName: string, file: File): Observable<any> {

   let headers = new HttpHeaders({
      'Access-Control-Allow-Origin': '*',
      'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
      'Access-Control-Allow-Headers': 'Content-Type,Accept,X-Access-Token,X-Key,Authorization,X-Requested-With,Origin,Access-Control-Allow-Origin,Access-Control-Allow-Credentials,content-type=multipart/*'
   })

  let options = {headers:headers, observer: 'response'};

  const formData: FormData = new FormData();

  formData.append('fileName', fileName);
  formData.append('file', file);

  const req = new HttpRequest('POST', this.url+'/fileUpload/upload', formData, {
    reportProgress: true,
    responseType: 'json'
  });

 return this.http.request(req);
}

请参阅此链接以了解更多信息formData


推荐阅读