1

How do you pull a new image (eg on a timer) from an AWS Signed URL from a React app.

The image is being displayed using an <img src=signedurl />

This is similar to this question, except using a typical cachebreaker (e.g. adding a random query string parameter) does not work. AWS does not allow for additional query strings and results in the following error:

<Error>
  <Code>SignatureDoesNotMatch</Code>
  <Message>
    The request signature we calculated does not match the signature you provided. Check your key and signing method.
  </Message>
  ...
</Error>

The structure I am trying to build this around is

  • client receives a pre-signed url (after authentication/authorization) to somebucket/some.jpg.
  • backend process is uploading a new image and replacing some.jpg every X minutes.
  • client needs to refresh every Y minutes and retrieve the most updated image.
jzacharuk
  • 2,058
  • 1
  • 16
  • 22
  • S3 doesn't support query string and it ignores them, It doesn't give you this error unless you have created a signed url and added something wrong in it. Try to add the query string in the CanonicalRequest. – James Dean Apr 14 '19 at 11:04
  • @JamesDean appending a query parameter to a URL that has alreasy been signed will also cause the error. I think that's what is being described, here. – Michael - sqlbot Apr 14 '19 at 14:47
  • @Michael-sqlbot just wondering if it's possible to include query string in signing process ? – James Dean Apr 15 '19 at 02:45
  • Yes, that is definitely possible in the sense that the actual signing algorithm allows it... however, whether the SDK you are using supports doing that is another matter. Is it the JS SDK or something else? – Michael - sqlbot Apr 15 '19 at 03:05
  • I am using the JS SDK, but I don't see how this would help. The Signed URLs should expire in a day. And the object is being updated in S3 every 5 seconds. It would not be ideal to have to grab a new signed url for every client every 5 seconds. I was hoping there was someway (other than query strings) to force a browser to reload img src. – jzacharuk Apr 15 '19 at 15:25

1 Answers1

1

I was able to resolve this. Pointing the img.src directly at the Signed Url left me with no way to force the browser to refresh the image.

However, I was able to fetch the image through the Signed Url in my React javascript instead, convert it to base 64, and then set the img.src to a data string. This can be set on a timer as needed.

const url ='signed url';

// Fetch from the signed url. Ensure that the image is not retrieved from cache
const response = await fetch(url, { cache: 'no-store' });
const buffer = await response.arrayBuffer();

// Convert from buffer to base64 (thanks [devlucky][1])
let binary = '';
const bytes = [].slice.call(new Uint8Array(buffer));
bytes.forEach(b => binary += String.fromCharCode(b));
const base64 = window.btoa(binary);

const src = `data:image/jpeg;base64,${base64}`;

this.setState({ src });
<img src={this.state.src}>
jzacharuk
  • 2,058
  • 1
  • 16
  • 22