redstone-dart / redstone

A metadata driven microframework for Dart.
http://redstone-dart.github.io/redstone
MIT License
342 stars 42 forks source link

Uploading a File #65

Closed cgarciae closed 9 years ago

cgarciae commented 9 years ago

I am trying to upload a file in Dart with this code

Reading the file

    dom.InputElement uploadInput = dom.querySelector('#upload');

    uploadInput.onChange.listen((dom.Event e) 
    {
        // read file content as dataURL
        final files = uploadInput.files;

        if (files.length == 1) 
        {
            final file = files[0];
            final reader = new dom.FileReader();

            reader.onLoad.listen((_) 
            {
                dataRequest('upload', reader.result);
            });

            reader.readAsDataUrl (file);
        }
    });

Sending the file

    Future<dom.HttpRequest> dataRequest (String path, dynamic data)
    {
        return dom.HttpRequest.request (path, method: "POST", 
               sendData: data);
    }

But I get this error

POST http://localhost:9090/upload 400 (Bad Request) :9090/upload:1
Instance of '_XMLHttpRequestProgressEvent'

STACKTRACE:
null

I receive it in Redstone like this

@app.Route("/upload", methods: const [app.POST], allowMultipartRequest: true)
@Encode()
upload(@app.Body(app.FORM) Map form) 
{
    var file = form["file"];
    print(file.filename);
    print(file.contentType);
    print(file.runtimeType);

    return new Resp()
        ..success = (file.filename != null);
}

I am doing something wrong on the client or on the server?

luizmineo commented 9 years ago

You can`t send the file data directly. Instead, you have to send a FormData object (or just submit a form). You can find some post about its usage on stackoverflow, like this one

cgarciae commented 9 years ago

Thanks! Now Redstone accepts the request. However I get a map like this

{ 'file' : 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQAB...'}

I've seen that if I manually use an input form (which I don't because then the browser tries to navigate to /upload) Redstone decodes the file to a HttpBodyFileUpload automatically. What can I add on the client upload to achieve the same effect?

cgarciae commented 9 years ago

My new client code looks like this

dom.FormData formData = new dom.FormData();
formData.append('file', data);

return dom.HttpRequest.request (path, method: "POST", 
           sendData: formData);
luizmineo commented 9 years ago

Try to apeend the file input element to the form, instead of the file data.

cgarciae commented 9 years ago

Thanks! It worked sending the FormElement and nowI have file is a HttpBodyFileUpload.

One last bit of help, I am guessing HttpBodyFileUpload.content is a binary representation of the image since its a List<int>, how can I convert and save this to disk as a png for example?

Thanks a lot!

luizmineo commented 9 years ago

Just create a File object (note that this is the File from dart:io, not dart:html) to write the data to the disk