我创建了一个带有烧瓶的web服务来保存文件,这强烈关注正式烧瓶example:
@app.route('/parse_table', methods=['POST'])
def upload_file():
print(request.files)
# check if the post request has the file part
if 'file' not in request.files:
print('no file in request')
return""
file = request.files['file']
if file.filename == '':
print('no selected file')
return""
if file and allowed_file(file.filename):
print("hello")
filename = secure_filename(file.filename)
file.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
return ""
print("end")
return""
当我在webapp中使用表单时,服务完美运行(文件将存储在服务器上)
<form action = "http://127.0.0.1:5000/parse_table" method = "POST"
enctype = "multipart/form-data">
<input type = "file" name = "file" /
<input type = "submit"/>
</form>
当尝试通过Angular HttpClient
处理上传时,flask会检测到请求中没有文件(即print('no file in request')
将被执行)
component.html
<input #fileInput name="file" type="file" (change)="handleFileInput($event.target.files)">
<button mat-raised-button class="standard-button" (click)="uploadFile()">Upload file</button>
component.ts
@ViewChild('fileInput') fileInput;
uploadFile() {
const files: FileList = this.fileInput.nativeElement.files;
if (files.length === 0) {
return;
};
this.backendCommunicationService.parseTable(files).subscribe((data: any) => {
console.log(data);
});
后端-communication.service.ts
parseTable(files) {
const httpOptions = {
headers: new HttpHeaders({
'Content-Type': 'multipart/form-data',
})
};
const formData: FormData = new FormData();
formData.append('file', files[0], files[0].name);
return this.http.post(this.backendAddress + '/parse_table', formData, httpOptions)
}
有任何建议/提示吗?
答案 0 :(得分:2)
删除httpOptions;例如,明确设置的http头,解决了问题。比较来自angular webapp和来自html表单的HTTP post请求,显示在http标头Content-Type中尽管有multipart/form-data'
边界,但是当显式设置http标头时,不需要使用angular设置边界。从http帖子中删除它解决了isuue:
parseTable(files) {
const formData: FormData = new FormData();
formData.append('file', files[0], files[0].name);
return this.http.post(this.backendAddress + '/parse_table', formData);
}
答案 1 :(得分:1)
如果您使用multipart/*
内容类型之一,则实际上需要在boundary
标头中指定Content-Type
参数,否则需要服务器(对于HTTP请求) )将无法解析有效负载。
来自RFC2046:
多部分实体的Content-Type字段需要一个参数, “边界”。然后将边界定界线定义为一条线 完全由两个连字符组成(“-”,十进制值45) 然后是Content-Type标头中的边界参数值 字段,可选的线性空格和终止CRLF。
边界分隔符不得出现在封装材料中, 且长度不能超过70个字符,不包括两个前导 连字符。
最后一个正文部分之后的边界定界线是 区分清楚的定界符,指示不再有其他身体部位 跟随。这样的定界符行与先前的定界符相同 行,在边界后再添加两个连字符 参数值。
因此,您的请求应如下所示
Content-Type: multipart/form-data; --unique-boundary-1
Content-Disposition: form-data; name="file"; filename="download.jpg"
--unique-boundary-1
在下图中查看Content-Type和Form数据
最好的实现此目标的方法是在Content-Type
中不包括HttpHeaders
。让浏览器根据您的内容为您添加它。
httpOptions = {
headers: new HttpHeaders({
// 'Content-Type': 'multipart/form-data', // comment this out
Authorization: this.userAuthContent
})
};
HTML
<input type="file" placeholder="Select images" accept="image/*" multiple
(change)="changeInFileInput($event.target.files)">
打字稿
changeInFileInput(files: any): void {
if (files) {
// iterate over all the files
Array.from(files).forEach((fileData: File) => {
// upload using promise
this.uploadImage(fileData.file)
.then((response: any) => {
// ...
})
.catch((error: any) => {
// ...
});
});
}
}
uploadImage(fileToUpload: File): Promise < any > {
return new Promise((resolve, reject) => {
// create form data
const formData: FormData = new FormData();
// append image file to it
formData.append('file', fileToUpload, fileToUpload.name);
// attach formData (just created above) and httpOptions (created earlier) to post request
this.httpClient.post(environment.bapiurls.uploadRefImage, formData, httpOptions)
.subscribe(
(response: any) => {
resolve(response);
},
(error: any) => {
reject(error);
});
});
}