2016-04-29 13 views
3

Ich arbeite an einer React Native-Anwendung, wo ich versuche, Bilder aus einer Benutzerrolle Kamera zu nehmen, sie in eine Base64-Zeichenfolge konvertieren und speichern sie für spätere Verwendung in Amazon S3.Saving base64 Zeichenfolge zu Amazon S3

Nach diesem Blog-Eintrag ich in der Lage bin eine Benutzerkamerarolle zu übernehmen und die Bilder zu Base64 konvertieren: react-native-creating-a-custom-module-to-upload-camera-roll-images

ich dann die base64 String Bilddaten auf einen einfachen Express-Server sende ich eingerichtet habe um die Daten in meinen Amazon S3-Bucket zu stellen.

// Only getting first img in camera roll for testing purposes 
CameraRoll.getPhotos({first: 1}).then((data) => { 

    for (let i = 0; i < data.edges.length; i++) { 
    NativeModules.ReadImageData.readImage(data.edges[i].node.image.uri, (imageBase64) => { 

     // Does the string have to be encoded? 
     // const encodeBase64data = encodeURIComponent(imageBase64); 

     const obj = { 
     method: 'POST', 
     headers: { 
      'Accept': 'application/json', 
      'Content-Type': 'application/json', 
     }, 
     body: JSON.stringify({ 
      'img': imageBase64 
     }) 
     } 

     fetch('http://localhost:3000/saveImg', obj) 
     .then((res) => { 
      console.log(JSON.parse(res._bodyInit)); 
     }) 

    }) 
    } 

Meine imageBase64 Variable in diesem Fall ist eine ziemlich große Zeichenfolge zu lesen wie: /9j/4AAQSkZJRgABAQAASABIAAD/4QBYRXhpZgAATU0AKgAAA...abX+Yub/API3zf8A7G2Z/wDqdiD/AExyf/kT5R/2Kst/9QqB0x6H6GuBbr1R6D2foz+ZT/gof/yep8bf934f/wDqC6PX96+Cn/JruFf+6z/6t8UfwP4wf8nM4n9Mq/8AVbRPjOv1I/OAoA//2Q== Mit dem ... mehrere Zeichen zu sein.

Ich sende diesen Base64-String zu meinem Express Server und veröffentliche die Daten:

app.post('/saveImg', function(req, res) { 

    // this will be moved once testing is complete 
    var s3Bucket = new AWS.S3({ params: {Bucket: '[my_bucket_name]'} }); 

    // Do I need to append this string to the image? 
    var baseImg = 'data:image/png;base64,' + req.body.img; 

    var data = { 
    Key: test_img, 
    Body: req.body.img, 
    ContentEncoding: 'base64', 
    ContentType: 'image/png' 
    }; 

    s3Bucket.putObject(data, function(err, data){ 
    if (err) { 
    console.log(err); 
    console.log('Error uploading data: ', data); 
    } else { 
    res.send(data); 
    console.log('successfully uploaded the image!'); 
    } 
}); 
    // res.send(base64data) 
}); 

ich erfolgreich die Daten auf Amazon S3 senden und meine Image-Datei auf dem heißen Stein jedoch sehen, wenn ich versuche, das zu besuchen Link, um das eigentliche Bild selbst zu sehen, oder ziehen Sie es in meine React Native App, bekomme ich nichts.

dh Wenn ich die URL oben besuchen, nachdem es in Amazon S3 erhalte ich:

https://s3.amazonaws.com/my_bucket_name/test_img 
This XML file does not appear to have any style information associated with it. The document tree is shown below. 
<Error> 
    <Code>AccessDenied</Code> 
    <Message>Access Denied</Message> 
    <RequestId>BCE6E07705CF61B0</RequestId> 
    <HostId> 
aF2l+ucPPHRog1QaaXjEahZePF0A9ixKR0OTzlogWFHYXHUMUeOf2uP7D/wtn7hu3bLWG8ulKO0= 

    </HostId> 
</Error> 

Ich habe Bilder manuell gleichen Eimer hochgeladen und ihre Links erscheinen in Ordnung, und ich bin zusätzlich in der Lage um sie in meine React Native-Anwendung zu ziehen, ohne Probleme beim Anzeigen.

Meine Frage ist, was mache ich falsch zwischen dem Abrufen der Base64-Zeichenfolge Daten und Senden an meinen Express-Server zum Speichern in meinem Eimer? Muss die Base64-Zeichenfolge codiert werden? Muss ich die base64-Zeichenfolge in einen Blob konvertieren, bevor ich sie an Express sende?

Danke für die Hilfe!

+0

Subscribing, ich brauche das auch –

Antwort

1

Es ist eine Erlaubnis Sache und hat nichts mit ReactNative noch Base64-Enconding zu tun.

du hast eine „AccessDenied“ -Fehler, das bedeutet, dass das Bild nicht öffentlich zugänglich ist. Nur wenn Sie Ihren Bucket mit den richtigen Berechtigungen konfigurieren (oder sogar die spezifische Datei, die ich im Folgenden erklären werde), erhalten Sie den Inhalt eines Bildes ohne signierte URLs.

Um zu untersuchen, ob dies die Ursache ist, können Sie versuchen, ein Bild in der s3-Konsole öffentlich zu machen. Gehen Sie einfach auf your s3-bucket und haben einen rechten Mausklick auf ein Bild-Datei:

enter image description here

Im Kontextmenü sind zwei interessante Artikel für Sie aufgelistet: „make public“ und " Öffnen Sie ".

Wenn Sie "öffnen" wählen, erhalten Sie eine "signierte URL" zu der Datei, was bedeutet, dass die einfache URL für das Bild mit bestimmten Parametern versehen wird, um diese Datei für eine Weile verfügbar zu machen:

enter image description here

Sie können auch ausprobieren „öffentlich machen“ und die Bild-uRL neu laden wieder zu sehen, ob es jetzt für Sie verfügbar sein wird.

1. Approach, eimer breit:

Eine Lösung ist eine IAM-Politik für den ganzen Eimer zu schaffen jedes Objekt in ihm öffentlich zu machen: zu

{ 
    "Version": "2008-10-17", 
    "Statement": [{ 
    "Sid": "AllowPublicRead", 
    "Effect": "Allow", 
    "Principal": { 
     "AWS": "*" 
    }, 
    "Action": [ "s3:GetObject" ], 
    "Resource": [ "arn:aws:s3:::YOUR_BUCKET_NAME/*" ] 
    }] 
} 

So geht Ihr Klicken Sie in der AWS-Konsole auf den Bucket und im rechten Bereich auf "Berechtigungen". Sie können eine neue Richtlinie wie die oben genannte erstellen.

enter image description here

2. Zweite Lösung, objektspezifische

Ein anderer Ansatz wäre ACL-specific headers zur putObject-Methode hinzuzufügen:

'ACL'   => 'public-read' 

Ich weiß nicht, Ihr Back-End -sdk, aber ich rate mal so:

var data = { 
    Key: test_img, 
    Body: req.body.img, 
    ContentEncoding: 'base64', 
    ContentType: 'image/png', 
    ACL: 'public-read', 
    }; 

Ich habe gerade die ACL-spezifische Zeile hier hinzugefügt. Je nach SDK kann es notwendig sein, die plain aws-Header "x-amz-acl: public-read" anstelle von "ACL: public-read" zu verwenden. Probieren Sie beide aus.

+0

Leider hat diese Lösung nicht für mich funktioniert. Ich habe die IAM-Policy für meinen Bucket hinzugefügt und wenn ich versuche, die Bilder, die von der Camera Roll gespeichert wurden, von ihren jeweiligen URLs zu laden, sehe ich nur ein kleines leeres weißes Quadrat oben links auf der Seite. Ich stellte sicher, dass die Bilder in meinem Eimer auch öffentlich waren, und ich bekomme immer noch das gleiche Problem. Es sind nur die Bilder, die ich von meiner Kamerarolle als Base64-String lade, die nicht so funktionieren, dass ich manuell hochgeladen habe, da Tests gut erscheinen. – Onaracs

0

Durch Hinzufügen von Bucket-Richtlinie zu Ihrem Bucket wird das Problem behoben.

2

Ich lief gerade in das gleiche Problem. Sie müssen die base64 Zeichenfolge in einen Blob vor dem Hochladen auf S3 konvertieren.

This answer erläutert, wie diese Konvertierung durchgeführt wird. Mit node-fetch, ist hier, wie in Ihrem Beispiel zu integrieren:

require('node-fetch') 

app.post('/saveImg', function(req, res) { 

    // this will be moved once testing is complete 
    var s3Bucket = new AWS.S3({ params: {Bucket: '[my_bucket_name]'} }); 

    var imageUri = 'data:image/png;base64,' + req.body.img; 

    fetch(imageUri) 
    .then(function(res){ return res.blob() }) 
    .then(function(image){ 
     var data = { 
     Key: test_img, 
     Body: image, 
     ContentEncoding: 'base64', 
     ContentType: 'image/png' 
     }; 

     s3Bucket.putObject(data, function(err, data){ 
     if (err) { 
     console.log(err); 
     console.log('Error uploading data: ', data); 
     } else { 
     res.send(data); 
     console.log('successfully uploaded the image!'); 
     } 
    }); 
    }) 
}); 

Sobald das erledigt ist, können Sie dann auf S3 das hochgeladene Bild in der Vorschau oder in Ihre Anwendung ziehen.