Codename one Upload a picture taken by the camera to amazon s3 bucket

喜你入骨 提交于 2019-12-08 04:32:27

问题


Original Question

I have tried as you have suggested, there are few things I have run into few issues. Here are the following I did: filePath = Capture.capturePhoto(1024, -1);

I had issue passing the S3_BUCKET_URL in the MutipartRequest Constructor so I used rq.setUrl(S3_BUCKET_URL)

I had to add rq.setHttpMethod("PUT"); // since I got error as 405: Method was not supported

Finally I got no errors and I did see a sub-folder created under the bucket I created. I set the url as "https://s3.amazonaws.com/bucket123/test/" I saw test bucket created but image files wasn't uploaded. The folder size wasn't 0 as it showed the size of the file but no image files were found in that sub folder.

When I try to access the folder through S3 explorer I got the the Access Denied. 1. I manually created a sub-folder using S3 explorer and gave the read and write permission yet once the uploadFileToS3 method called from codename I saw the permissions was lost. 2. So I did change the acl to "public-read-write" still same effect.

Please advise if I am missing anything.

Thank you.


Modified question I have modified the old questions and following this with Sahi's answer.

    // Modified the url as following - full path including bucket name and key
    private static final String S3_BUCKET_URL = "https://s3.amazonaws.com/my-bucket/myfile.jpg";

    //String filePath = captured from Camera;
        public void uploadFileToS3(String filePath, String uniqueFileName) {
            MultipartRequest rq = new MultipartRequest();
            rq.setUrl(S3_BUCKET_URL);
            //rq.addArgument("acl", "private");
            //rq.addArgument("key", uniqueFileName);
            rq.addData(uniqueFileName, filePath, "image/jpeg");
            rq.setReadResponseForErrors(true);
            NetworkManager.getInstance().addToQueue(rq);
        }

Now I do see that the file has been uploaded to the bucket as myfile.jpg under my bucket.  The bucket has all the rights since the bucket is given rights to read and write also applied the permissions to sub folders.
Now the myfile.jpg lost all the permissions and I am not able to download that file even though I see it in the bucket.
I accessed it by the url but the file cannot be opened.

I am not sure what I am missing in the header or request. I am really trying to get this working but not getting where I wanted to.  This is very important piece for the app I am working on.  

Please provide any feedback.

Thank you.

--------------------------------------------------------------------------

Adding code

private static final String S3_BUCKET_URL = "https://s3.amazonaws.com/my-bucket/";

When I had the url as above, the my-bucket was created as unknown object (no folder icon) but I did see the file size was actual image size.

//String filePath = captured from Camera;
public void uploadFileToS3(String filePath, String uniqueFileName) {
//uniqueFileName including sub folder - subfolder/my-image.jpg
MultipartRequest rq = new MultipartRequest();
rq.setUrl(S3_BUCKET_URL);
rq.addArgument("acl", "public-read-write");
rq.addArgument("key", uniqueFileName);
rq.addData(uniqueFileName, filePath, "image/jpeg");
rq.setReadResponseForErrors(true);
NetworkManager.getInstance().addToQueue(rq);
}

Looks like I am not uploading the object properly. I did go through the amazon document and I wasn't able to find anything related to upload through http. I am really stuck and I hope to get this resolved. Would you have any working code that simply uploads to s3?


More details: I am adding more detail to the question as I am still not able to resolve this.

    // Original S3_BUCKET_URL 
    String S3_BUCKET_URL = "https://s3.amazonaws.com/my-bucket/";
    // With this url I am getting 400 : Bad Request Error
    // I added the uniqueFilename (key) to the url as 
    String uniqueFilename = "imageBucket/image12345.jpg";
    String S3_BUCKET_URL = "https://s3.amazonaws.com/my-bucket   /"+uniqueFilename;
    //Now I do see the file I believe it's the file, the 
    //subfolder inherits the rights from bucket (read, write). 
    //Not the image file.
    //When I click on the file using s3 client browser I got message
    //prompted Access Denied.

    // my function to call s3 bucket
    public void takePicture()
    {
        String stringImg = Capture.capturePhoto(1024, -1);    
        MultipartRequest rq = new MultipartRequest();
        rq.setUrl(S3_BUCKET_URL);
        rq.addArgument("key", uniqueFilename );
        rq.addArgument("acl", "public-read-write");
        rq.setHttpMethod("PUT"); // If I don't specify this I am getting 
                                 // 405 : Method Not Allowed Error.
        rq.addData("file", stringImg, "image/jpeg"); 
        //Captured Image from camera
        rq.setFilename("file", uniqueFilename);
        NetworkManager.getInstance().addToQueue();
    }

At this point I believe I have done all the suggested way and I am still getting the same error. I believe I am not doing anything wrong and I don't want to believe that I am the only one trying to do this :)

I really need your help to get this resolved in order to keep this project. I am wondering if there is any Amazon s3 sdk or library I can use in codename one.

Please review this and let me know if this really can be achieved by codename one.

Thank you.


回答1:


I've tested this code and it should work however it depends on a fix to Codename One to deal with some stupid behavior of the Amazon API:

Form hi = new Form("Upload");

Button upload = new Button("Upload");
hi.add(upload);
upload.addActionListener(e -> {
    String file = Capture.capturePhoto();
    if(file != null) {
        try {
            String uniqueFileName = "Image" + System.currentTimeMillis() + ".jpg";
            MultipartRequest rq = new MultipartRequest();
            rq.setUrl("https://s3.amazonaws.com/my-bucket/");
            rq.addArgument("key", uniqueFileName);
            rq.addArgument("acl", "private");
            rq.addData("file", file, "image/jpeg");
            rq.setReadResponseForErrors(true);
            NetworkManager.getInstance().addToQueueAndWait(rq);            
            if(rq.getResponseCode() != 200 && rq.getResponseCode() != 204) {
                System.out.println("Error response: " + new String(rq.getResponseData()));
            }
            ToastBar.showMessage("Upload completed", FontImage.MATERIAL_INFO);
        } catch(IOException err) {
            Log.e(err);
        }
    }
});

hi.show();

When running the code below (with post) I didn't get the error you described, instead I got an error from Amazon indicating the key wasn't in the right order. Apparently Amazon relies on the order of the submitted fields which is damn stupid. Unfortunately we ignore that order when you add an argument and since this is a post request the code to workaround this is non-trivial.

I've made a fix to Codename One that will respect the natural order in which arguments are added but since we already made this weeks release this will only go in next Friday (December 23rd 2016). So the code above should work as expected following that update.

Older answer for reference

I haven't tested this but something like this should work:

private static final String S3_BUCKET_URL = "https://s3.amazonaws.com/my-bucket/";


public void uploadFileToS3(String filePath, String uniqueFileName) {
    MultipartRequest rq = new MultipartRequest(S3_BUCKET_URL);
    rq.addArgument("acl", "private");
    rq.addArgument("key", uniqueFileName);
    rq.addData("file", filePath, "image/jpeg");
    rq.setFilename("file", uniqueFileName);
    rq.setReadResponseForErrors(true);
    NetworkManager.getInstance().addToQueue(rq);
}

Notice that this doesn't do authorization so it assumes the bucket is accessible at least for write.




回答2:


  1. Generate a presigned URL on you server:

  2. Pass thar URL to the mobile client.

    IAmazonS3 client;
    client = new AmazonS3Client(Amazon.RegionEndpoint.USEast1);
    // Generate a pre-signed URL.
    GetPreSignedUrlRequest request = new GetPreSignedUrlRequest
        {
           BucketName = bucketName,
            Key        = objectKey,
            Verb       = HttpVerb.PUT,
            Expires    = DateTime.Now.AddMinutes(5)
        };
    string url = null;
    url = s3Client.GetPreSignedURL(request);
    
  3. Mobile client can upload a file to that URL using old plain PUT HTTP request:

    // Upload a file using the pre-signed URL.
    HttpWebRequest httpRequest = WebRequest.Create(url) as HttpWebRequest;
    httpRequest.Method = "PUT";
    using (Stream dataStream = httpRequest.GetRequestStream())
    {
       // Upload object.
    }
    
    HttpWebResponse response = httpRequest.GetResponse() as HttpWebResponse;
    

You can take a look at official documentation at http://docs.aws.amazon.com/AmazonS3/latest/dev/UploadObjectPreSignedURLDotNetSDK.html



来源:https://stackoverflow.com/questions/41094606/codename-one-upload-a-picture-taken-by-the-camera-to-amazon-s3-bucket

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!