react-native-background-upload icon indicating copy to clipboard operation
react-native-background-upload copied to clipboard

Failed to upload file directly to S3

Open thangnt-savvy opened this issue 3 years ago • 4 comments

I tried to upload a file directly to S3, but my order of parameters is not as required. Seem I can't change the order of my request.

Here is my code

  const options: any = {
    url: url,
    path: path,
    method: 'POST',
    type: 'multipart',
    field: 'file',
    maxRetries: 2, // set retry count (Android only). Default 2
    headers: {
      'content-type': fileInfo.mimeType, // server requires a content-type header
      'content-length': `${fileInfo.size}`,
    },
    parameters: {
      key: `${fields.key}/${fileInfo.name}`,
      acl: fields['acl'],
      bucket: fields['bucket'],
      'X-Amz-Algorithm': fields['X-Amz-Algorithm'],
      'X-Amz-Credential': fields['X-Amz-Credential'],
      'X-Amz-Date': fields['X-Amz-Date'],
      'X-Amz-Signature': fields['X-Amz-Signature'],
      Policy: fields['Policy'],
      'Content-Type': fileInfo.mimeType,
    },
    notification: {
      enabled: true,
    },
    useUtf8Charset: true,
  };

  Upload.startUpload(options)
    .then(uploadId => {
      console.log('Upload started');
      Upload.addListener('progress', uploadId, data => {
        console.log(`Progress: ${data.progress}%`);
      });
      Upload.addListener('error', uploadId, data => {
        console.log(`Error: ${data.error}%`);
      });
      Upload.addListener('cancelled', uploadId, data => {
        console.log('Cancelled!', data);
      });
      Upload.addListener('completed', uploadId, data => {
        // data includes responseCode: number and responseBody: Object
        console.log('Completed!', data);
      });
    })
    .catch(err => {
      console.log('Upload error!', err);
    });

and S3 error message Key should be the first item instead of file

<?xml version="1.0" encoding="UTF-8"?>
<Error>
  <Code>InvalidArgument</Code>
  <Message>Bucket POST must contain a field named 'key'.  If it is specified, please check the order of the fields.</Message>
  <ArgumentName>key</ArgumentName>
  <ArgumentValue></ArgumentValue>
</Error>

thangnt-savvy avatar May 24 '22 04:05 thangnt-savvy

Hi there, we got to work with pre-signed URLs. The change needed is to send it with PUT and type 'raw'.

anyb1s avatar Jun 01 '22 03:06 anyb1s

@anyb1s right I also using pre-signed URL with some configurations but it only seems like work in simulators any ideas why is not working on the real devices

nodabasi avatar Jun 20 '22 10:06 nodabasi

Hi there, we got to work with pre-signed URLs. The change needed is to send it with PUT and type 'raw'.

Hi, I am having the same problem. @anyb1s , if I use type 'raw' I get an error that I cannot pass extra parameters: Error: Parameters supported only in multipart type

How did you make it work on your side? I need to send the parameters that contain the amazon policies and so on to make the pre-signed URL work. Thanks!

frank137 avatar Jun 22 '22 16:06 frank137

What we do is the following we have an endpoint to presign `$command = $adapter->getClient()->getCommand('putObject', array_filter([ 'Bucket' => $adapter->getBucket(), 'Key' => $path, 'ACL' => 'public-read', 'ContentType' => $request->get('type'), 'Metadata' => [ 'content-type' => $request->get('type'), ] ]));

    $signedRequest = $adapter->getClient()->createPresignedRequest($command, '+5 minutes');

    return response()->json([
        'method' => $signedRequest->getMethod(),
        'url' => (string)$signedRequest->getUri(),
        'fields' => [],
        'path' => 'tmp/' . $filename,
        'headers' => [
            'content-type' => $request->get('type'),
        ],
    ]);`

const options = { url: presignResponse.url, path: imagePath, method: presignResponse.method, type: 'raw', field: 'file', maxRetries: 2, // set retry count (Android only). Default 2 headers: { 'content-type': mimeType, // Customize content-type accept: 'application/json', // Customize content-type }, // Below are options only supported on Android notification: { enabled: true, autoclear: true, onProgressTitle: 'Uploading...', onCompleteTitle: 'Upload finished', }, useUtf8Charset: true, };

anyb1s avatar Jun 23 '22 12:06 anyb1s