4

Angular 4 Flask 1.0.2

Hi all

I am trying to upload a file from Angular by populating a new FormData() object and posting it. It appears to be posting ok, but I can't get the values from the post from within Flask.

I call this from a button click event:

UploadFile() : void{
    let formModel = new FormData()
    formModel.set('fileName', this.fileName);
    formModel.set('fileData', this.form.get('fileData').value);

    this.filesProvider.UploadFile(formModel)
      .subscribe(res => {
      this.UploadFileProcessed(res, true);
    }
    , (err) => {
      this.UploadFileProcessed(err, false);
    }
);

...which calls a provider...

UploadFile(formData: FormData) : Observable<Response> {

    let headers = new Headers();
    headers.set('Content-Type', null);
    headers.set('Accept', "multipart/form-data");
    headers.set('Authorization', 'Basic ' + btoa(access_token + ":"));
    let requestOptions = new RequestOptions({ headers: headers })

    return this.http
    .post(this.globalVarsProvider.apiUrl + "member/uploadFile", formData, requestOptions)
    .map((response: Response) => response);
}

On the Flask API end I have this:

@app.route('/api/member/uploadFile', methods=['POST'])
@auth.login_required
def uploadFile(): 
    print request.form.get('key1')
    return "ok"

Running this outputs "None" in the Flask dev server terminal.

If I do print request.get_data() I see all the post data (including the crazy image data stuff).

In Chrome the request looks like this:

enter image description here

Any idea what I'm doing wrong please and how I get the data from within Flask?

Thanks!

Doug
  • 665
  • 2
  • 8
  • 22

1 Answers1

8

You did two things wrong:

  • You set the Content-Type header to null, so it is left empty. Now Angular can't tell the server how to split out the different parts of a multipart/form request.

  • You are not accessing the correct fields on the server side.

You should not set the Content-Type header at all, so remove the headers.set('Content-Type', null) call. Angular 4 then sets the header for you, to multipart/form-data and will include the boundary value (the string betwen fields in the request body) in that header.

Your Flask code is trying to access a non-existing field. Your frontend code posts two fields:

formModel.set('fileName', this.fileName);
formModel.set('fileData', this.form.get('fileData').value);

and your screenshots confirm that fileName and fileData parts are indeed posted. But your Flask code tries to access key1:

print request.form.get('key1')

There is no such key, so the .get() method returns the default value, None, instead.

For file uploads, you really want to use request.files attribute; see the documentation for that attribute and for the requests.form attribute:

form: A MultiDict with the parsed form data from POST or PUT requests. Please keep in mind that file uploads will not end up here, but instead in the files attribute.

[...]

files: A MultiDict with files uploaded as part of a POST or PUT request. Each file is stored as FileStorage object. It basically behaves like a standard file object you know from Python, with the difference that it also has a save() function that can store the file on the filesystem.

So use request.form['fileName'] and request.files['fileData'] to access the two fields.

Also see the Uploading Files pattern documentation.

As a side note: You should not set the Accept header. The Accept header is there for a client (such as your browser) to tell the server what kind of responses are acceptable. Accept: multipart/form tells the server that you want it to respond with a multipart/form response. It says nothing about the content of the request itself. If you got your example from a comment to this blog post (a top Google hit for "angular 4 form-data upload"), then that commenter has mislead you with non-working code. I've added a comment there to at least help future visitors avoid that error.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Thank you, this completely sorted it for me. Greatly appreciated. Thank you also for the clear explanation. It was the [article you mentioned](https://nehalist.io/uploading-files-in-angular2/) that I had followed. – Doug Aug 09 '18 at 12:24
  • [https://pythonhosted.org/Flask-Uploads/][1] is a Flask plugin to simplify File Uploads. [1]: https://pythonhosted.org/Flask-Uploads/ – Julien Cochennec Aug 11 '18 at 12:48