使用 Angular2 将文件上传到 REST API

新手上路,请多包涵

实际上,我正在使用一个用 Angular 2 编码的接口开发一个 Spring REST API。

我的问题是我无法使用 Angular 2 上传文件。

我在 java 中的 Webresources 是:

 @RequestMapping(method = RequestMethod.POST, value = "/upload")
public String handleFileUpload(@RequestParam MultipartFile file) {
    //Dosomething
}

当我通过带有 Auth 标头等的 URL 请求调用它时,它工作正常……(使用 Chrome 的 Advanced Rest Client 扩展)

证明:(在那种情况下一切正常)

在此处输入图像描述 我添加了

<bean id="multipartResolver"
      class="org.springframework.web.multipart.commons.CommonsMultipartResolver" />

Spring配置文件和Pom依赖

<dependency>
    <groupId>commons-fileupload</groupId>
    <artifactId>commons-fileupload</artifactId>
    <version>1.2</version>
</dependency>

但是当我尝试用网络表单做同样的事情时:

 <input type="file" #files (change)="change(files)"/>
<pre>{{fileContents$|async}}</pre>

使用(更改)方法:

 change(file) {
    let formData = new FormData();
    formData.append("file", file);
    console.log(formData);
    let headers = new Headers({
        'Authorization': 'Bearer ' + this.token,
        'Content-Type': 'multipart/form-data'
    });
    this.http.post(this.url, formData, {headers}).map(res => res.json()).subscribe((data) => console.log(data));
    /*
    Observable.fromPromise(fetch(this.url,
        {method: 'post', body: formData},
        {headers: this.headers}
    )).subscribe(()=>console.log('done'));
    */
}

我的网络服务返回错误 500,在 tomcat 日志中:http: //pastebin.com/PGdcFUQb

我也尝试了 'Content-Type': undefined 方法但没有成功(在这种情况下,Web 服务返回 415 错误。

有人可以帮我弄清楚问题出在哪里吗?

问题已解决,稍后我将用我的代码更新该问题 :) 但是,看看它运行良好的 plunker。谢谢。

原文由 Slater 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 557
2 个回答

这在最终版本中实际上很容易做到。我花了一些时间来思考它,因为我遇到的大多数关于它的信息都已经过时了。在这里发布我的解决方案以防其他人为此苦苦挣扎。

 import { Component, ElementRef, Input, ViewChild } from '@angular/core';
import { Http } from '@angular/http';

@Component({
    selector: 'file-upload',
    template: '<input type="file" [multiple]="multiple" #fileInput>'
})
export class FileUploadComponent {
    @Input() multiple: boolean = false;
    @ViewChild('fileInput') inputEl: ElementRef;

    constructor(private http: Http) {}

    upload() {
        let inputEl: HTMLInputElement = this.inputEl.nativeElement;
        let fileCount: number = inputEl.files.length;
        let formData = new FormData();
        if (fileCount > 0) { // a file was selected
            for (let i = 0; i < fileCount; i++) {
                formData.append('file[]', inputEl.files.item(i));
            }
            this.http
                .post('http://your.upload.url', formData)
                // do whatever you do...
                // subscribe to observable to listen for response
        }
    }
}

然后像这样使用它:

 <file-upload #fu (change)="fu.upload()" [multiple]="true"></file-upload>

这真的就是它的全部。

或者,捕获事件对象并从 srcElement 获取文件。老实说,不确定是否有任何方法比另一种更好!

请记住 FormData 是 IE10+,所以如果你必须支持 IE9,你将需要一个 polyfill。

更新时间 2017-01-07

更新的代码能够处理多个文件的上传。此外,我的原始答案缺少有关 FormData 的相当关键的一点(因为我将实际的上传逻辑移动到我自己的应用程序中的单独服务,我在那里处理它)。

原文由 Brother Woodrow 发布,翻译遵循 CC BY-SA 3.0 许可协议

事实上,目前,您只能为 Angular2 HTTP 支持的 postputpatch 方法提供字符串输入。

为此,您需要直接利用 XHR 对象,如下所述:

 import {Injectable} from 'angular2/core';
import {Observable} from 'rxjs/Rx';

@Injectable()
export class UploadService {
  constructor () {
    this.progress$ = Observable.create(observer => {
      this.progressObserver = observer
    }).share();
  }

  private makeFileRequest (url: string, params: string[], files: File[]): Observable {
    return Observable.create(observer => {
      let formData: FormData = new FormData(),
        xhr: XMLHttpRequest = new XMLHttpRequest();

      for (let i = 0; i < files.length; i++) {
        formData.append("uploads[]", files[i], files[i].name);
      }

      xhr.onreadystatechange = () => {
        if (xhr.readyState === 4) {
          if (xhr.status === 200) {
            observer.next(JSON.parse(xhr.response));
            observer.complete();
          } else {
            observer.error(xhr.response);
          }
        }
      };

      xhr.upload.onprogress = (event) => {
        this.progress = Math.round(event.loaded / event.total * 100);

        this.progressObserver.next(this.progress);
      };

      xhr.open('POST', url, true);
      xhr.send(formData);
    });
  }
}

有关详细信息,请参阅此插件: https ://plnkr.co/edit/ozZqbxIorjQW15BrDFrg?p=info。

在 Angular 仓库中有一个问题和一个未决的 PR:

原文由 Thierry Templier 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题