cant upload image on aws s3 via nodejs and flutter with presigned url

1,110

S3 Presigned URLs require raw bytes as the body, not multipart files. Thus, I used the following code:

List<int> content = await file.readAsBytes();

var streamed = http.StreamedRequest("PUT", Uri.parse(url));
streamed.headers["Content-Type"] = mimeType;
streamed.headers["Content-Length"] = "${content.length}";
streamed.sink.add(content);
streamed.sink.close();

var response = await streamed.send();
Share:
1,110
arnabbabai
Author by

arnabbabai

Updated on December 09, 2022

Comments

  • arnabbabai
    arnabbabai over 1 year

    i was trying to do image upload with dart/flutter with aws s3 bucket with presigned url via nodejs. i successfully generated the presigned url and send it back to front end but cant not make the put request over s3 with the file.if i am printing the statuscode i am getting a 400.

     import 'dart:io';
    import 'dart:convert';
    import 'package:path/path.dart';
    import 'package:async/async.dart';
    import 'package:flutter/material.dart';
    import 'package:image_picker/image_picker.dart';
    import 'package:http/http.dart' as http;
    import 'package:http_parser/http_parser.dart';
    import 'package:mime/mime.dart';
    import '../global.dart';
    
    class AddAccount extends StatelessWidget {
      Widget build(context) {
        return Scaffold(
          appBar: AppBar(
            iconTheme: IconThemeData(
              color: Colors.grey
            ),
            title: Text('Add Account', style: TextStyle(color: Colors.black54, fontSize: 20.0)),
            backgroundColor: Colors.white,
          ),
          body: addAccountBody(context),
        );
      }
      Widget addAccountBody(context){
        return ListView(
          children: <Widget>[
            TextField(
              decoration: InputDecoration(
                labelText: 'email'
              ),
              textCapitalization: TextCapitalization.characters,
            ),
    
            TextField(
              decoration: InputDecoration(
                labelText: 'name'
              ),
              textCapitalization: TextCapitalization.characters,
            ),
            OutlineButton(
              onPressed: (){
                openImagePicker(context);
              },
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  Icon(Icons.camera_alt),
                  Text('add image')
                ],
              ),
            )
          ],
        );
      }
      void openImagePicker(BuildContext context){
        showModalBottomSheet(
          context: context,
          builder: (BuildContext context) {
            return Container(
              height: 80.0,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                children: <Widget>[
                  IconButton(
                    onPressed: (){
                      getImage(context, ImageSource.camera);
                    },
                    icon: Icon(Icons.camera_alt),
                  ),
                  SizedBox(width: 20.0,),
                  IconButton(
                    onPressed: () async {
                      File image = await getImage(context, ImageSource.gallery);
                      http.Response response = await http.get('$url1/api/upload', headers: {
                        "x-auth" : 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJfaWQiOiI1YzQ0M2M0NDE0NjkxODM3ZTQxNTMxZTgiLCJhY2Nlc3MiOiJhdXRoIiwiaWF0IjoxNTQ3OTc1NzQ5fQ.73_tyhu3vTpsnMncmjTS0xDBec08pScxpa35yRlLuzQ'
                      });
                      Map<String, dynamic> uploadUrl = json.decode(response.body);
                      final dataType = lookupMimeType(image.path).split("/");
                      final imageUploadRequest = http.MultipartRequest("PUT", Uri.parse(uploadUrl['url']));
                      final file = await http.MultipartFile.fromPath("${uploadUrl['key']}", image.path, contentType: MediaType(dataType[0], dataType[1]));
                      imageUploadRequest.files.add(file);
                      imageUploadRequest.fields['user'] = Uri.encodeComponent('user');
                      imageUploadRequest.headers['Content-Type'] = 'image/jpeg';
                      print(file.contentType);
                      try{
                        final streamedResponse = await imageUploadRequest.send();
                        final res = await http.Response.fromStream(streamedResponse);
                         print(res.statusCode);
                      }catch(e){
                        print(e);
                      }
                    },
                    icon: Icon(Icons.camera),
                  ),
    
                ],
              ),
            );
          }
        ); 
      }
      Future<File> getImage(BuildContext context, ImageSource sourse) async {
        File file = await ImagePicker.pickImage(source: sourse, maxWidth: 400.0);
        Navigator.pop(context);
        return file;
    
      }
    }
    

    flutter code

        const AWS = require('aws-sdk');
    const uuid = require('uuid/v1');
    const keys = require('../config/keys');
    const { authenticate } = require('../middleware/authenticate')
    
    const s3 = new AWS.S3({
        accessKeyId: keys.accessKeyId,
        secretAccessKey: keys.secretAccessKey
    });
    
    module.exports = (app) => {
        app.get('/api/upload', authenticate, (req,res) => {
            console.log(req.user.id);
            const key = `${req.user.id}/${uuid()}.jpeg`;
            s3.getSignedUrl('putObject', {
                Bucket: 'flutter-bucket',
                ContentType: 'image/jpeg',
                Key: key
            }, (err, url) => {
                res.send({key, url});
            })
        });
    }
    

    node code