3

We recently moved our website to Amazon S3 (all static pages). We moved al static files to a different subdomain which still points to our old server.

All is working lovely except one thing.

We got a script that's still being called from old clients on the main domain. On the new clients, the URL is fixed, but the old clients are still using the old URL.

I found we can manage redirects in Amazon S3 as described on http://docs.aws.amazon.com/AmazonS3/latest/dev/how-to-page-redirect.html . This is working, except the fact we are loosing all our GET-variables.

Is there a way to define a S3 redirect with forwarding/keeping the GET-variables? How can we fix this problem the best? Any idea's?

John Rotenstein
  • 241,921
  • 22
  • 380
  • 470
Jelle De Laender
  • 577
  • 3
  • 16

2 Answers2

9

By "GET data," it sounds like you are referring to the query string -- e.g. ?foo=1&bar=2 -- that follows the path in your URL. This is removed by S3 when you do object-level redirects.

Instead of redirecting specific objects, you can use routing rules to redirect requests for all objects with a specific prefix to a different web site, and optionally you can do this redirect only if an error (such as 404) would occur while trying to serve the original object. Using this method, the query string seems to be consistently preserved.

To redirect every nonexistent object at http://example.com/this/directory/* to http://other-site.example.com/that/directory/* you'd use a rule something like this:

<RoutingRule>
    <Condition>
        <KeyPrefixEquals>this/directory/</KeyPrefixEquals>
        <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>
    </Condition>
    <Redirect>
        <Protocol>http</Protocol>
        <HostName>other-site.example.com</HostName>
        <ReplaceKeyPrefixWith>that/directory/</ReplaceKeyPrefixWith>
    </Redirect>
</RoutingRule>

<HttpErrorCodeReturnedEquals> is not required if you want to redirect every object request matching that prefix to the other site, even when the object already exists in the bucket where the rule is configured. <ReplaceKeyPrefixWith> could be set to the same values as <KeyPrefixEquals> or possibly omitted entirely, if you don't need to rewrite the path prefix.

Note that you don't use a leading slash in the prefix-related options.

Note also that the correct value you'll want to use for <HttpErrorCodeReturnedEquals> may be 403 ("Forbidden") instead of 404 ("Not Found"). Objects in S3 can be made public by either bucket-level or object-level permissions. If the bucket itself is not publicly-readable, the objects still can be, if their permissions are set individually. When the bucket itself is not publicly-readable, (iirc) S3 will not acknowledge whether the object exists or not, with a 404 on an unauthenticated request, and will instead generate the 403 error, so that's the error you'll need to trap in the redirect rules.

Michael - sqlbot
  • 169,571
  • 25
  • 353
  • 427
  • Wonderful! Using redirects is indeed saving the URL-parameters. Adjusted the code to work on only one file, it's also 403 as Amazon S3 is giving 'no permission' rather than not found, but with that, it seems to work as it should :) Thanks! – Jelle De Laender Jun 03 '14 at 11:37
  • Excellent. Thank you for mentioning 403... I seem to remember encountering that before, also. I believe that would be the case, when the public readability of the objects in the bucket is being set using object-level instead of with bucket-level permissions. Updated the answer. – Michael - sqlbot Jun 03 '14 at 14:36
  • 1
    @Michael-sqlbot The query string no longer seems to be preserved. Any ideas? – Andrew Rasmussen Jun 11 '15 at 07:53
  • @arasmussen I can't duplicate what you're describing. I just now tested against one of my buckets, and can verify that the behavior of a bucket using redirect rules is still consistent with the information here. The query string from the request is still being preserved in the rewritten URL returned in the `Location:` header. Can you capture the output of `curl -v [url]`? I may be able to address it here or we may need a new question, depending on what you find. – Michael - sqlbot Jun 11 '15 at 17:37
  • 1
    @Michael-sqlbot figured it out! I had CloudFront configured to not forward query strings. Thanks for your response though! See http://stackoverflow.com/questions/30775068/amazon-s3-redirect-rule-preserve-query-params/30798325#30798325 – Andrew Rasmussen Jun 12 '15 at 08:10
  • They querystring gets forwarded but the routing parameters e.g. when forwarding /Invoice/{invoiceid} to /index.html for SPA client side routing, the invoiceId doesn't get forwarded, – nabeelfarid Jun 23 '21 at 14:29
0

The key is to use ReplaceKeyPrefixWith instead of ReplaceKeyWith.

With Gulp and gulp-awspublish for instance, the config is in JSON.

So going from:

Condition:
  KeyPrefixEquals: 'us.html'
Redirect:
  ReplaceKeyWith: 'about.html'

To

Condition:
  KeyPrefixEquals: 'us.html'
Redirect:
  ReplaceKeyPrefixWith: 'about.html'

Will make example.com/us.html?a=1 redirect to example.com/about.htmk?a=1.

Be careful of loops, eg.

Condition:
  KeyPrefixEquals: 'about'
Redirect:
  ReplaceKeyPrefixWith: 'about.html'

Will make a redirect loop by adding .html.html.html etc.

Dorian
  • 22,759
  • 8
  • 120
  • 116