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!

0

1 Answer 1

9

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this completely sorted it for me. Greatly appreciated. Thank you also for the clear explanation. It was the article you mentioned that I had followed.
[pythonhosted.org/Flask-Uploads/][1] is a Flask plugin to simplify File Uploads. [1]: pythonhosted.org/Flask-Uploads

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.