Tosin Awofeso
Tosin Awofeso

Reputation: 31

Using signed requests with AWS S3 and uploading photos?

So I have a react native application that's kind of like slack and I'm trying to do image uploads to s3.

I went with getSignedUrl route.

So the client pics a photo, fetches a signed url to the bucket then changes the url on the server for that user then a put request to the signed url that was fetched.

It mostly works the files get in the right bucket and they are photos. but

A) the link makes me download the file instead of displaying it in browser.

B) the file isn't an image...its an xml file and can only be opened in photoshop

I've tried changing the type in the data.append type, Adding header to the signed request Adding x-amz- headers to the signed request hard coding the file type in server converting image to base64 string with a native module but It still is coming up wrong.

Client Side calls to server

uploadToServer() {

    // alert('coming soon!');

    //Go back to profile page
    this.props.navigation.goBack();

    //grab user from navigator params
    let user = this.props.navigation.state.params.user
    let pic = this.state.selected;

    // turn uri into base64
    NativeModules.ReadImageData.readImage(pic.uri, (image) => {
      console.log(image);

      var data = new FormData();
      data.append('picture', {
        uri: image,
        name: pic.filename,
        type: 'image/jpeg'
      });

      //get the signed Url for uploading
      axios.post(api.getPhotoUrl, {fileName: `${pic.filename}`}).then((res) => {

        console.log("get Photo URL response", res);

        //update the user with the new url
        axios.patch(api.fetchUserByID(user.id), {profileUrl: res.data.url}).then((resp) => {

          console.log("Update User response", resp.data);
        }).catch(err => errorHandler(err));

        //upload the photo using the signed request url given to me.
        //DO I NEED TO TURN DATA INTO A BLOB?
        fetch(res.data.signedRequest, {
          method: 'PUT',
          body: data
        }).then((response) => {
          console.log("UPLOAD PHOTO RESPONSE: ", response);
        }).catch(err => errorHandler(err))
      }).catch((err) => errorHandler(err))
    })
  }

GET SIGNED URL logic from on out

router.post('/users/sign-s3', (req, res) => {
      const s3 = new aws.S3({signatureVersion: 'v4', region: 'us-east-2'});
      const fileName = `${req.user.id}-${req.body.fileName}`;
      const fileType = req.body.fileType;
      const s3Params = {
        Bucket: AWS_S3_BUCKET,
        Key: `images/${fileName}`,
        Expires: 60,
        ContentType: 'image/jpeg',
        ACL: 'public-read'
      };

      s3.getSignedUrl('putObject', s3Params, (err, data) => {
        if (err) {
          console.log(err);
          return res.end();
        }
        const returnData = {
          signedRequest: data,
          url: `https://${AWS_S3_BUCKET}.s3.amazonaws.com/${s3Params.Key}`
        };
        res.write(JSON.stringify(returnData));
        res.end();
        return null;
      });
    });

Upvotes: 1

Views: 933

Answers (1)

Kush Vyas
Kush Vyas

Reputation: 6079

You need to change content type from image to supported xml format if you want it to be displayed in browser.

Refer this and set content type accordingly.

Upvotes: 1

Related Questions