使用Angular 6向Flask(Python)Web服务上传文件

使用Angular 6向Flask(Python)Web服务上传文件,angular,flask,Angular,Flask,我使用flask创建了一个Web服务来保存文件,它严格遵循了flask: 当我在我的webapp中简单地使用表单时,该服务可以完美地工作,文件将存储在服务器上 <form action = "http://127.0.0.1:5000/parse_table" method = "POST" enctype = "multipart/form-data"> <input type = "file" name = "file" / <in

我使用flask创建了一个Web服务来保存文件,它严格遵循了flask:

当我在我的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>
组件技术

后端-communication.service.ts


有什么建议/提示吗

删除httpOptions;e、 显式设置的http头解决了这个问题。比较来自angular webapp和html表单的HTTP post请求表明,在HTTP头内容类型中,尽管有多部分/表单数据,但需要一个边界,当显式设置HTTP头时,angular不会设置该边界。从http post中删除此选项可解决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);
}

删除http选项;e、 显式设置的http头解决了这个问题。比较来自angular webapp和html表单的HTTP post请求表明,在HTTP头内容类型中,尽管有多部分/表单数据,但需要一个边界,当显式设置HTTP头时,angular不会设置该边界。从http post中删除此选项可解决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);
}
如果您使用的是multipart/*内容类型之一,则实际上需要在内容类型标头中指定边界参数,否则,在HTTP请求的情况下,服务器将无法解析有效负载

发件人:

多部分实体的内容类型字段需要一个参数, 边界然后将边界分隔线定义为一条线 完全由两个连字符组成,十进制值45 后跟内容类型标题中的边界参数值 字段、可选线性空白和终止的CRLF

边界分隔符不得出现在封装材质中, 且不得超过70个字符,不包括两个前导字符 连字符

最后一个主体部分后面的边界分隔线是 可分辨分隔符,指示不再显示其他身体部位 跟随这样的分隔符行与前面的分隔符相同 线条,并在边界后添加两个以上连字符 参数值

因此,您的请求应该是

Content-Type: multipart/form-data; --unique-boundary-1
Content-Disposition: form-data; name="file"; filename="download.jpg"

--unique-boundary-1
查看下图中的内容类型和表单数据

在angular中,实现这一点的最佳方法是不在HttpHeader中包含内容类型。让浏览器根据您的内容为您添加它

httpOptions = {
    headers: new HttpHeaders({
        // 'Content-Type': 'multipart/form-data', // comment this out
        Authorization: this.userAuthContent
    })
};
HTML

打字稿

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);
        });
  });
}
如果您使用的是multipart/*内容类型之一,则实际上需要在内容类型标头中指定边界参数,否则,在HTTP请求的情况下,服务器将无法解析有效负载

发件人:

多部分实体的内容类型字段需要一个参数, 边界然后将边界分隔线定义为一条线 完全由两个连字符组成,十进制值45 后跟内容类型标题中的边界参数值 字段、可选线性空白和终止的CRLF

边界分隔符不得出现在封装材质中, 且不得超过70个字符,不包括两个前导字符 连字符

最后一个主体部分后面的边界分隔线是 可分辨分隔符,指示不再显示其他身体部位 跟随这样的分隔符行与前面的分隔符相同 线条,并在边界后添加两个以上连字符 参数值

因此,您的请求应该是

Content-Type: multipart/form-data; --unique-boundary-1
Content-Disposition: form-data; name="file"; filename="download.jpg"

--unique-boundary-1
查看下图中的内容类型和表单数据

在angular中,实现这一点的最佳方法是不在HttpHeader中包含内容类型。让浏览器根据您的内容为您添加它

httpOptions = {
    headers: new HttpHeaders({
        // 'Content-Type': 'multipart/form-data', // comment this out
        Authorization: this.userAuthContent
    })
};
HTML

打字稿

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);
        });
  });
}

您好,我刚刚遇到了同样的问题,我可以问您为什么在删除了标题后它会工作吗?谢谢你嗨,我刚刚遇到了同样的问题,我可以问你为什么它在移除了头的工作人员后工作吗?非常感谢。
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);
        });
  });
}