Angular - POST上传文件
Angular - POST上传文件
我正在使用Angular和TypeScript向服务器发送文件,以及JSON数据。
以下是我的代码:
import { Component, View, NgFor, FORM_DIRECTIVES, FormBuilder, ControlGroup } from 'angular2/angular2';
import { Http, Response, Headers } from 'http/http';
@Component({ selector: 'file-upload' })
@View({
directives: [FORM_DIRECTIVES],
template: `
文件上传
选择文件:
`
})
export class FileUploadCmp {
public file: File;
public url: string;
headers: Headers;
constructor(public http: Http) {
console.log('文件上传已初始化');
//设置头部为multipart
this.headers = new Headers();
this.headers.set('Content-Type', 'multipart/form-data');
this.url = 'http://localhost:8080/test';
}
//文件改变监听器
changeListener($event): void {
this.postFile($event.target);
}
//发送文件到服务器
postFile(inputValue: any): void {
var formData = new FormData();
formData.append("name", "Name");
formData.append("file", inputValue.files[0]);
this.http.post(this.url,
formData,
{
headers: this.headers
});
}
}
我应该如何将formData转换为字符串并发送到服务器?我记得在AngularJS(v1)中,你会使用transformRequest。
Angular - POST上传文件的问题出现的原因是因为Angular2的http模块尚不支持文件上传。为了解决这个问题,可以使用以下的服务函数作为一种解决方法:
uploadFile(file:File):Promise{ return new Promise((resolve, reject) => { let xhr:XMLHttpRequest = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState === 4) { if (xhr.status === 200) { resolve( JSON.parse(xhr.response)); } else { reject(xhr.response); } } }; xhr.open('POST', this.getServiceUrl(), true); let formData = new FormData(); formData.append("file", file, file.name); xhr.send(formData); }); }
然而,为了使其工作,需要在xhr.open的行之后添加`xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');`。如果需要授权,可以在xhr.open的行之后添加`xhr.setRequestHeader('Authorization', 'Bearer ' + __your_auth_key__);`。
目前还不支持文件上传,可以查看问题状态github.com/angular/http/issues/75。虽然链接已更新,但仍然没有直接支持进度,因为fetch功能缺乏此功能,而Angular不希望将http API与XHR绑定在一起。
我正在使用全新的Angular 4,似乎他们还没有修复这个问题。要么是我没理解对,要么就是文件从未传递过来。谢谢你的函数,我让它工作了。谢谢你。
目前还没有来自Angular的支持-github.com/angular/angular/issues/37597。
Angular - POST上传文件
问题的出现原因:
在调用postWithFile函数时,未正确传递文件。在调用函数的组件文件中,通过event对象获取上传的文件,但是代码中却错误地使用了event.srcElement.files来获取文件,导致出现了"error TS2339: Property 'files' does not exist on type 'Element'."的错误。
解决方法:
在调用函数的组件文件中,将onChange函数修改为onChange(event),以正确传递event对象。这样就可以通过event.target.files来获取文件。
整理代码如下:
你的http服务文件:
import { Injectable } from "/core"; import { ActivatedRoute, Router } from '/router'; import { Http, Headers, Response, Request, RequestMethod, URLSearchParams, RequestOptions } from "/http"; import {Observable} from 'rxjs/Rx'; import { Constants } from './constants'; declare var $: any; @Injectable() export class HttpClient { requestUrl: string; responseData: any; handleError: any; constructor(private router: Router, private http: Http, private constants: Constants, ) { this.http = http; } postWithFile(url: string, postData: any, files: File[]) { let headers = new Headers(); let formData: FormData = new FormData(); formData.append('files', files[0], files[0].name); // For multiple files // for (let i = 0; i < files.length; i++) { // formData.append(`files[]`, files[i], files[i].name); // } if (postData !== "" && postData !== undefined && postData !== null) { for (var property in postData) { if (postData.hasOwnProperty(property)) { formData.append(property, postData[property]); } } } var returnResponse = new Promise((resolve, reject) => { this.http.post(this.constants.root_dir + url, formData, { headers: headers }).subscribe( res => { this.responseData = res.json(); resolve(this.responseData); }, error => { this.router.navigate(['/login']); reject(error); } ); }); return returnResponse; } }
调用你的函数(组件文件):
onChange(event) { let files = event.target.files; let postData = {field1: "field1", field2: "field2"}; // Put your form data variable. This is only an example. this._service.postWithFile(this.baseUrl + "add-update", postData, files).then(result => { console.log(result); }); }
你的HTML代码:
其中一个唯一使用了Angular的答案
如何解决"error TS2339: Property 'files' does not exist on type 'Element'."错误
将onChange() {...}
修改为onChange(event) {...}
将修复错误:property files does not exist 😉
对我不起作用。它无法在后端使用multer的节点中找到该文件。
问题的出现原因:在上传文件时,代码中使用了async/await来处理异步操作,但最新的Chrome浏览器beta版本可以读取任何通过TypeScript编译的es6代码,因此必须将asyns/await替换为.then()。
解决方法:将代码中的async/await替换为.then()。
文章如下:
文件上传问题 - Angular中的POST上传文件
最近我在编写代码时遇到了一个问题,但请注意,我使用了async/await,因为最新的Chrome浏览器beta版本可以读取任何通过TypeScript编译的es6代码。所以,你必须将asyns/await替换为.then()。
下面是我代码中的一部分:
文件输入变化处理程序:
/** * fileInput */ public psdTemplateSelectionHandler(fileInput: any) { let FileList: FileList = fileInput.target.files; for (let i = 0, length = FileList.length; i < length; i++) { this.psdTemplates.push(FileList.item(i)); } this.progressBarVisibility = true; }
提交处理程序:
public async psdTemplateUploadHandler(): Promise{ let result: any; if (!this.psdTemplates.length) { return; } this.isSubmitted = true; this.fileUploadService.getObserver() .subscribe(progress => { this.uploadProgress = progress; }); try { result = await this.fileUploadService.upload(this.uploadRoute, this.psdTemplates); } catch (error) { document.write(error) } if (!result['images']) { return; } this.saveUploadedTemplatesData(result['images']); this.redirectService.redirect(this.redirectRoute); }
文件上传服务:
import { Component } from 'angular2/core'; import { Injectable } from 'angular2/core'; import { Observable } from 'rxjs/Observable'; import 'rxjs/add/operator/share'; export class FileUploadService { private progress$: Observable; private progress: number = 0; private progressObserver: any; constructor() { this.progress$ = new Observable(observer => { this.progressObserver = observer }); } public getObserver(): Observable { return this.progress$; } public upload(url: string, files: File[]): Promise { return new Promise((resolve, reject) => { 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) { resolve(JSON.parse(xhr.response)); } else { reject(xhr.response); } } }; FileUploadService.setUploadUpdateInterval(500); 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); }); } private static setUploadUpdateInterval(interval: number): void { setInterval(() => { }, interval); } }
此外,我还需要添加以下代码才能使其正常工作:
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
在上传XML文件时,它会自动在文件中添加' ------WebKitFormBoundaryklb8qUzyCQJSI440 Content-Disposition: form-data; name="file" '。我不想在传输过程中添加额外的数据到文件中,你知道如何解决吗?另外,上传jpg格式的图片后,它不再是jpg文件了。所以我的问题是:如何在传输过程中保持原始文件?
为什么我们需要setInterval()
?
希望以上内容能帮助到你。