react router doesn't work in aws s3 bucket
Asked Answered
K

20

165

I deployed my React website build/ folder into an AWS S3 bucket.

If I go to www.mywebsite.com, it works and if I click on a tag to go to Project and About pages, it leads me to the right page. However, if I copy and send the page url or go straight to the link like: www.mywebsite.com/projects, it returns 404.

Here's my App.js code:

const App = () => (
    <Router>
        <div>
            <NavBar/>
            <Switch>
                <Route exact path="/" component={Home}/>
                <Route exact path="/projects" component={Projects}/>
                <Route exact path="/about" component={About}/>
                <Route component={NoMatch}/>
            </Switch>
        </div>
    </Router>
);
Kemper answered 7/7, 2018 at 0:21 Comment(3)
I don't think this is an issue with React Router, but rather that your server is not serving your index.html and bundle.js on any other route than /. It needs to serve those files on all routes.Accordion
Possible dupe of https://mcmap.net/q/138313/-redirection-to-error-page-in-amazon-s3-static-website. You need to redirect errors (404 in this case) to the root index.htmlClerk
actually, bundle.js is called explicitly whenever index.html is served. So what you need is to make sure that index.html is served on any path you expect to support deep-linking, and it will call bundle.js appropriately. If you don't have a 404 file - make index.html your 404. If you do - use an explicit paths list in your cloudfront behaviors.Om
K
123

Update 1 May 2020:

Since this post is quite active, I need to update the answer:

So you have a few options to solve the issue:

  1. You can put index.html in the Error document box (like Alan Friedman suggested).
    • Go to your bucket (the one that actually has the code - not the one you use to redirect) -> Properties -> Static website hosting:
    • This is not "hacky" but it works because of the way react-router works: It handles the requests from the front-end and routes users to other routes but overall, the React app is a single-page application.
    • If you want server-side React, consider using Next.js.

enter image description here

  1. You can put a designated error file error.html in the public folder of your React app and in the Static website hosting: Error document box, put in: error.html. This also works. I've tested it.

  2. Use AWS CloudFront > CloudFront Distributions > The distribution of your bucket > Error Pages and add the error code you want. If you don't use react-router (like the example below), the bucket will respond with Error 403 so you can respond with your error.html.

enter image description here

  1. For TypeScript, currently react-router doesn't support it so you should consider option 2 and 3. They're going to update the library in future version 6.* according to this thread.
Kemper answered 15/9, 2018 at 15:35 Comment(4)
This is very hacky, but also the solution I use. What I don't like about it is that the 404 still happens, it just gets redirected.Spleenwort
Be aware of one consequence of this ... if your web page includes a src="/static/somescript.js" where somescript.js does not actually exist, or where access is denied to the requested script, then the browser's request will yield the content of the index.html file rather than the JS file and that will be parsed as JavaScript by the browser and result in JavaScript parsing errors of "<!doctype html> ..." Similarly for CSS files or other assets.Dianetics
This solution impacts SEO. Google doesn't rank well sites that throw 404s.Fuzee
how do you add custom header for the errors page? #69183784Molybdic
B
217

I'm not sure if you have already solved it. I had the same issue.

It's because AWS S3 is looking for that folder (projects) to serve from, which you don't have.

Simply point Error document to index.html.

enter image description here

This worked for me. You can handle error pages in react-router.

Boyce answered 15/9, 2018 at 9:44 Comment(10)
Thanks, AR. Yes I have solved it thanks to Alan Friedman's comment above.Kemper
small things. when I hit a path, in the console it says 404 not found - as we are redirecting it to the error page. I'm not convinced. There might be a better way.Boyce
This did work for me as well but don't you think we should do apply redirection rules instead? I don't know how to, yet. I'm still looking into it.Caramelize
You mean adding redirection rules in aws S3?Boyce
This is not the correct answer... because you will have another error, check this question: #59160972Husky
Yes. This is obviously a hack. For the right solution, you might need to add S3 redirection rules. Also, try using HashRouter(instead of BrowserRouter) from react-router. This might workBoyce
Although this solution works, it impacts SEO. Google will rank your website worse than others that don't throw as many 404s. I learned this the hard way.Fuzee
@LuisGouveia how did you go ahead then? what did you do?Decry
@sumanthshetty check my comment on "Amr Abu Greedah" answer! Have a nice dayFuzee
how do you add custom header for the errors page? #69183784Molybdic
K
123

Update 1 May 2020:

Since this post is quite active, I need to update the answer:

So you have a few options to solve the issue:

  1. You can put index.html in the Error document box (like Alan Friedman suggested).
    • Go to your bucket (the one that actually has the code - not the one you use to redirect) -> Properties -> Static website hosting:
    • This is not "hacky" but it works because of the way react-router works: It handles the requests from the front-end and routes users to other routes but overall, the React app is a single-page application.
    • If you want server-side React, consider using Next.js.

enter image description here

  1. You can put a designated error file error.html in the public folder of your React app and in the Static website hosting: Error document box, put in: error.html. This also works. I've tested it.

  2. Use AWS CloudFront > CloudFront Distributions > The distribution of your bucket > Error Pages and add the error code you want. If you don't use react-router (like the example below), the bucket will respond with Error 403 so you can respond with your error.html.

enter image description here

  1. For TypeScript, currently react-router doesn't support it so you should consider option 2 and 3. They're going to update the library in future version 6.* according to this thread.
Kemper answered 15/9, 2018 at 15:35 Comment(4)
This is very hacky, but also the solution I use. What I don't like about it is that the 404 still happens, it just gets redirected.Spleenwort
Be aware of one consequence of this ... if your web page includes a src="/static/somescript.js" where somescript.js does not actually exist, or where access is denied to the requested script, then the browser's request will yield the content of the index.html file rather than the JS file and that will be parsed as JavaScript by the browser and result in JavaScript parsing errors of "<!doctype html> ..." Similarly for CSS files or other assets.Dianetics
This solution impacts SEO. Google doesn't rank well sites that throw 404s.Fuzee
how do you add custom header for the errors page? #69183784Molybdic
B
50

In case this S3 bucket is served from a CloudFront distribution:

Create a custom error page (AWS Docs) in CloudFront distribution that routes 404 errors to index.html and returns 200 response code. This way your application will handle the routing.

Custom Error Pages

enter image description here

Brandy answered 21/11, 2019 at 15:27 Comment(5)
YES I had to add 403 as wellEtherege
Wouldn't this have the undesirable behaviour of routing legitimate 404s to index.html, including for images etc.? Sometimes you do want to have a real 404.Understudy
That's the idea behind "your application will manage the routing". Each request goes through your index.html (single page application) and your application's router returns the relevant response. This means you keep the routing logic in the app itself, while avoiding the maintenance of another routing logic in CloudFront. This is just a nice trick which makes the developer's life easier - routing as a one stop shop, no need to know anything about AWSBrandy
Well, except that your application in this case is client-side, not server-side. As such, as 'application' you cannot signal any longer that a resource has not been found. I think that you should make a distinction between routes and files that will be handled by the application and routes that will be handled by S3 or cloudfront.Aculeus
Yes It works for me as wellWalczak
R
33

Redirecting 4xx to index.html would work, but that solution would make you fall into many other problems like google won't be able to crawl these pages. Please check this link, it solved this issue by using redirection rules for the S3 bucket.

Ripley answered 22/4, 2020 at 22:9 Comment(9)
Your answer rocks! It should be the accepted answer, as the accepted one is sub-optimal and has very inconvenient impacts on SEO (because google doesn't like sites that return 404s). If anybody's searching @Amr Abu Greedah equivalent for the Microsoft world, I recommend to check the following answer: https://mcmap.net/q/138316/-azure-app-service-not-working-with-custom-routing-in-react-redux-web-app-need-wildcard-virtual-directoriesFuzee
Just in case using the xml format is failing, try using a json version for your redirection rules. That's what I had to do for this solution to work for meAusterity
Definitely, the right answer. I was searching for this way too long.Weinberg
Solves the issue of index.html loading relative css/js filesHarakiri
Not a good answer. This would add a # to the URL and look very ugly. It reminds me of the Flash days or early AngularJS days. The previous answer is not fully working for me as well as I have both frontend and backend on the same distribution (multiple origins) Refreshing the page gives me an XML error: 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>...</RequestId> <HostId>...</HostId> </Error>Forsta
@Forsta I haven't tried this solution yet but I'm not sure about your comment "This would add a # to the URL and look very ugly.". According to the linked blog post, we can preffity as follows: "Then we need to add a little code to our React app to change the url back to our friendly format (because #!/ urls are gross)."Perreault
As of March 2023, XML doesn't work. Also, IMHO putting an extra # in the URL isn't a very good ideaLuisaluise
This is a perfect answer to the problem. It solves issues for React apps with routing.Sling
We did this #! method initially, and it works well for Google. However, it causes Bing to not index our pages. Now we're looking for another way.Antagonist
P
19

There are some good answers in this thread mostly around configuring your S3 bucket with redirection rules. Although this would have also worked for my use case, which is typically hosting a React single page application using React Router through CloudFront with S3 configured as the Origin, I decided to try a different approach given a kind of new feature which was recently released, CloudFront Functions. The main idea is to rewrite the URL before it reaches CloudFront cache so that URLs created by React Router on the client side are rewritten to point to the application domain root.

You can read more about CloudFront Functions here: https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/cloudfront-functions.html

The main idea is to use a CloudFront Function for rewriting the request Uri for any requests that are not targeting static files, i.e .js, .CSS, .html etc... and making it point to the /index.html file. This function would run as part of the viewer request trigger and run before CloudFront checks to see whether the requested object is in the CloudFront cache. That would result in any Uri sent by the client that is generated by the React Router to be rewritten before the content is requested from the origin server, thus not requiring to do any further redirects on S3. At the same time, files that are requested but do not exist anymore on the origin would return a 404 as expected, while all other static content would be served as requested.

Here is how my CloudFront function looks like:

function handler(event) {
  var request = event.request;

  if (!request.uri.includes('.')) {
    request.uri = "/index.html";
    request.querystring = {}
  }

  return request;
}

You can make the URL re-writing rules as complex as you like, but surprisingly, this small piece of code works fine for my use case. Also, unlike Lambda@Edge functions, CloudFront Functions are much more lightweight and allow you to experiment almost real time through AWS console by changing the code of your function there, testing it and deploying it within a couple seconds. However, they come with certain language limitations, so do not expect all JavaScript language features to be supported. This page documents what is available for you to use:

https://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/functions-javascript-runtime-features.html

Passional answered 21/11, 2021 at 22:43 Comment(5)
Nice solution, I was looking for the same. This feels right for 2022.Corvin
Awesome and clean solution! Works perfectly. I was worried I'll have to switch to Lambda@Edge just to cater for this 404 use case.Mcduffie
this is great but what about preserving the querystring? v5.reactrouter.com/web/example/query-parametersBoney
Very solid solution.Dy
Should be the real solution. The others destroy 404s or require you to make S3 the webserver which is inefficient since cloudfront is also a webserver.Allveta
S
17

Below configuration resolved enter image description here

Updated error pages in associated cloud-front distribution with custom error response from http status code 404-not-found to code 200-OK at response page path as / and near zero time-to-live

Sight answered 28/6, 2021 at 11:4 Comment(2)
@Kemper this should get marked as the answer. It achieves the same behavior as all the suggestions for lambda, but without additional cost and minimal additional complexity.Flocculate
Were you really trying to scramble the CF id on your screenshot ?Ragg
H
11

100% Working and Tested to host SPA website like React in S3 Bucket and fix 404 sub pages issue

  1. Login to amazon console
  2. search for Cloud front
  3. Select your Distributions
  4. Select Error Pages tab and Click on Create custom Error Response enter image description here
  5. Create a response rule here enter image description here
  6. Save error rule

You have Done!

Hispanicize answered 23/3, 2022 at 17:48 Comment(2)
This is a great answer and much easier than editing the redirect rules for the static website. Thanks a ton for thisVenerate
Nice, this one is trickyElegance
J
9

Case use Cloudfront to S3:

https://hackernoon.com/hosting-static-react-websites-on-aws-s3-cloudfront-with-ssl-924e5c134455

3b) AWS CloudFront — Error Pages After creating the CloudFront distribution, while its status is In Progress, proceed to the Error Pages tab. Handle response codes 404 and 403 with Customize Error Response.

Google recommends 1 week or 604800 seconds of caching. What we are doing here is to set up CloudFront to handle missing html pages, which typically occurs when a user enters an invalid path or, in particular, when they refresh a path other than the root path.

When that happens:

CloudFront will be looking for a file that does not exist in the S3 bucket; there is only 1 html file in the bucket and that is the index.html for the case of a Single Page Application like this project example A 404 response will be returned and our custom error response setup will hijack it. We will return a 200 response code and the index.html page instead. React router, which will be loaded along with the index.html file, will look at the url and render the correct page instead of the root path. This page will be cache for the duration of the TTL for all requests to the queried path. Why do we need to handle 403 as well? It is because this response code, instead of 404, is returned by Amazon S3 for assets that are not present. For instance, a url of https://yourdomain.com/somewhere will be looking for a file called somewhere (without extension) that does not exist.

PS. It used to be returning 404, but it seems to be returning 403 now; either way it is best to handle both response codes).

Jeanette answered 18/6, 2019 at 19:13 Comment(3)
This worked for me. It is the same as https://mcmap.net/q/137147/-react-router-doesn-39-t-work-in-aws-s3-bucket but for cloudfrontMonarchism
This worked! Been through loads of articles on this the 403 was the missing link - thank youGot
Contrary to what the article says, this doesn't just apply to html pages. Any 404, including for images etc., will redirect index.html, which is quite ugly.Understudy
A
9

This question already has several great answers. Although the question is now old, I faced this problem today, so I feel that perhaps this answer can help.

S3 has two kinds of end points, and if you are facing this error, you have probably selected the S3 bucket directly as the endpoint in the Origin Domain Name field for your CloudFront Distribution.

This would look something like: bucket-name.s3.amazonaws.com and is a perfectly valid endpoint. In fact, it would seem that AWS does expect this as default behaviour; this entry will be in the drop-down list you have when you are creating your CloudFront distribution.

However, doing this and then setting error pages may or may not solve your problem.

S3 has, however, a dedicated Website Endpoint. This is accessible from your S3 Bucket > Properties > Static Website Hosting. (You will see the link on the top).

You should use this link instead of the original auto-populated link that comes up in CloudFront. You can put this in while creating your distribution, or after creation, you can edit from the tab Origins and Origins Groups, and then invalidating caches.

This link will look like: bucket-name.s3-website.region-name.amazonaws.com.

Once this propagates and changes, this should then fix your problem.

tl;dr: Don't use the default S3 endpoint in CloudFront. Use the S3 website endpoint instead. Your origin domain should look like this: my-application.s3-website.us-east-1.amazonaws.com and not like my-application.s3.amazonaws.com.

More Information about website endpoints is available in the AWS Documentation here.

Ainsworth answered 22/4, 2020 at 17:17 Comment(3)
That works. But then, why would you need cloudfront and benefitting from SSL and multi-region distribution?Chelseachelsey
@PatrickBassut I don't quite understand your question. But note from the linked doc that an S3 website endpoint "Does not support SSL connections". So in order to give the end user an SSL connection, you need CloudFront. That's my understanding. Here is another doc that seems to support this use case: aws.amazon.com/premiumsupport/knowledge-center/…. Also, another use case for CloudFront is speed of content delivery. So there are two reasons to use CloudFront here. Am I misunderstanding your question?Perreault
This is perfect.Trabzon
P
9

There are many answers here so I thought I would do a survey of the existing ones to date, and compare pros and cons of the various approaches.

Approach Description Pros Cons Answers
CloudFront Function Use an AWS CloudFront function to write requests to the root document of the SPA e.g. index.html No error thrown, no redirection, apparently good for SEO. AWS suggest this approach in one of their docs. Extra cost (although at the time of writing this the free tier allows 2M invocations free per month and after that it's only 10c per million invocations). Extra infrastructure to deploy/manage. KG
Host as website Configure the S3 bucket to host a website, rather than a REST API. Routing handled automatically by S3 when it's configured this way. Can't use Orign Access Identity. Rather, the S3 endpoint is exposed over HTTP and you need to restrict access using custom headers, which is more complicated. FV
Error Redirection (404 and 403) The vast majority of answers seem to offer some flavour of this. The idea is to allow the 404 or 403 error to happen, but then return index.html (or whatever the SPA root document is) as the error page. Easy to implement. Causes a redirect for the client every time they try to access a non-root URL. Apparently this can be bad for SEO. AR, V, MG, PB, K, KS
URL Hashes / Hashbangs Some solutions involve routing sub-pages using hashes in the URLs. No redirection & no cost for extra AWS resources. There seem to be issues with these approaches - see here. Hashes in URLs are considered ugly by some; there do seem to be ways to mitigate this, but that involves some extra complexity. AA, B

Note: I am basing this answer on what I've read in other answers. I have not fully tested any approach except for the "CloudFront Function" approach, which I can confirm works.

Perreault answered 31/5, 2022 at 15:8 Comment(0)
P
5

This thread has been really helpful for me. I know this is old, but, I'd like to add a aws-cdk code snippet that finally worked for me. My use case needed me to utilize aws-cdk, so, I'm adding it here if you're looking forward to a aws-cdk based solution.

The code snippet adds index.html as error page in s3 and also in cloudfront. For cloudfront specifically, I added the error page as /index.html for 404 and 403 with a response of 200


// imports...
// import * as cdk from '@aws-cdk/core';
// import * as s3 from '@aws-cdk/aws-s3';
// import * as cloudfront from '@aws-cdk/aws-cloudfront';

// following code snippet has to be added in a 
// class which extends to a Construct or a Stack

    const bucket = new s3.Bucket(this, '<Specify a name>', {
      bucketName: '<add your bucket name>',
      websiteIndexDocument: 'index.html',
      websiteErrorDocument: 'index.html',
      blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL,
      removalPolicy: cdk.RemovalPolicy.DESTROY, // edit it according to your use case, I'll change it though
      autoDeleteObjects: true,
    });

    const cloudFrontOAI = new cloudfront.OriginAccessIdentity(this, 'OAI');

    const distribution = new cloudfront.CloudFrontWebDistribution(this, props?.stackName + 'AbcWebsiteDistribution', {
      defaultRootObject: "index.html",
      errorConfigurations: [{
        errorCode: 404,
        responsePagePath: "/index.html",
        responseCode: 200
      }, {
        errorCode: 403,
        responsePagePath: "/index.html",
        responseCode: 200
      }],
      originConfigs: [
        {
          s3OriginSource: {
            s3BucketSource: bucket,
            originAccessIdentity: cloudFrontOAI,
            originPath: "/artifacts" // change this based on your use case
          },
          behaviors: [{ isDefaultBehavior: true }]
        }
      ]
    })

    bucket.grantRead(cloudFrontOAI.grantPrincipal);

Answers that really helped me from this thread are:

https://mcmap.net/q/137147/-react-router-doesn-39-t-work-in-aws-s3-bucket

https://mcmap.net/q/137147/-react-router-doesn-39-t-work-in-aws-s3-bucket

https://mcmap.net/q/137147/-react-router-doesn-39-t-work-in-aws-s3-bucket

Perineum answered 31/1, 2021 at 6:24 Comment(1)
thanks, I'm using cdk too and was looking for thisStolid
M
3

I'm going to add yet another method, because the CloudFront Function option is great, except that it returns soft-404s, which are bad for your SEO.

This method uses both a CloudFront Function and CloudFront Distribution Custom Error Page to return valid URIs with 200 status codes, and invalid URIs with 404 status codes.

The Function:

This particular function is designed for the routing configuration specified in the React Router v6 Quick Start guide, where /invoices and /expenses are nested under the root route /, plus a catch-all route for 404s *. It redirects requests to the URIs included in the validPaths array to /index.html, allowing other requests through as-is. You should adapt this function to reflect the valid URIs of your SPA, and you may elect to change how this function checks the request.uri against the validPaths.

function handler(event) {
    var request = event.request;

    var validPaths = ['/','/invoices','/expenses'];

    if( validPaths.includes(request.uri) ){
        request.uri = "/index.html"
    } 
     
    return request;
}

Any valid static asset requests will still return static assets, but invalid requests to either pages or assets will return an error in XML with a 403 status code.

The Error Handler:

If we combine this with a custom error response that turns 403s into 404s + /index.html, we have an app that will allow React Router to work correctly, without returning soft 404s! Your local search engine crawler will be happy.

CloudFront Distribution Custom Error Response Form image link, because I don't have enough points for it show up inline.

Other Thoughts:

The downside of this approach is that the list of valid URIs in the function must be maintained manually. There are other approaches similar to this that are discussed in this article.

Note that for this approach, you should be using the REST API as your endpoint, with access restricted by an OAI, and not the S3 static website endpoint. This will ensure all traffic to your website is through your CloudFront distribution, protecting private content (if applicable) but also ensuring that your CloudFront logs, if you use them, are complete.

Mccammon answered 25/6, 2022 at 0:21 Comment(1)
If I already have a behavior "redirect HTTP to HTTPS" would you recommend I add this function to that existing behavior, or create a second behavior?Aneurysm
H
2

here is my solution without using cloudfront

  1. setting error page to index.html
  2. add redirect rule to top when 404 error

enter image description here

Haga answered 19/5, 2023 at 8:17 Comment(0)
T
1

I ran into this issue despite using the configuration as described in the accepted answer, but if you still get 403 errors, AND you're using AWS Cloudflare Manager, you can create an error page in the "Error Pages" tab of the distribution settings, with the following configuration:

Error Code: 404,
Customize Error Response: Yes, 
Response Page Path: /index.html, 
HTTP Response Code: 200

Pic of Error Page Config to pass route handling to browser router

This worked for me although I'm by no means knowledgeable about proper server admin, hopefully someone will tell me if this is a major issue, if serendipitous.

Turin answered 7/3, 2019 at 7:44 Comment(3)
403 = forbidden. Are you sure your bucket or object is public?Kemper
I did the same as @worc: CloudFront > Error pages > Create custom error response > 403 or 404, depending on your error > Customize Error Response: Yes > Response Page Path: /index.html > HTTP Response Code: 200Ordeal
You will have in cloud front an error x-cache error from cloudfrontHusky
B
1

update config of s3 with hosting static and default with index.html enter image description here

add CloudFront with error page

404 error-> index.html->status 200

enter image description here

Brinn answered 5/10, 2020 at 1:58 Comment(0)
K
0

Why it happens

Your issue is that you want to pass responsibility to routing to your react app/javascript. The link will work because react can listen to the link click and simply update the route in the browser URL bar. However, if you go a location where your script (index.html and the bundle.js or wherever your app code is located) is not loaded, then the JavaScript is never loaded and has no chance to handle the request. Instead, whatever runs your server will take care of the request, look if there is a resource at this place, and return a 404 error or whatever else it found.

The solution

As mentioned in the comments, this is the reason why you need to redirect 404-errors to the exact location where your app is placed. This is nothing specific to Amazon, it is a general requirement to set up your react app.

To solve the issue you need to find out what handles routing on your server and how to configure it. For example if you have an Apache server, an .htaccess file could take care of the matter like this:

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteBase /
    RewriteRule ^index\.html$ - [L]
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule . /index.html [L]
 </IfModule>

This file lets the server redirect not found errors to the index.html. Keep in mind that it might affect other routing rules that are on your server, so this configuration is easiest, if your react app has a place on its own, not interfering with other stuff.

Kalinda answered 7/7, 2018 at 9:51 Comment(3)
So that means I get an http request every time I hit a link in React?Froze
@ItayMoav-Malimovka No that is not the case. It happens only once you enter the application/type in the initial URL. Here the server decides what to server to the client - in this case the React app. From then on the React router takes over, changing the displayed URL, history etc. without the server knowing.Kalinda
this is about routing on s3. no server in betweenLycaonia
A
0

As per previous answers, the best way to solve the problem: redefine the fallback strategy. If you'd like to learn more about client-side routing vs server-side, and particularly about different routing approaches in the React JS, check out this article.

Aramaic answered 28/1, 2020 at 22:57 Comment(2)
This solution seems to suffer from a couple of issues: 1) Although the page content is returned correctly, the http response code is still 404. 2) It will capture 404 requests for things like images etc and route them to index.htmlUnderstudy
Good call, if it is an issue, I'd suggest to use redirect rules, Redirect Rules. One row below the error page configuration. Example 3: Redirect for an HTTP error from the doc would be a good starting poing. In the <Condition> part we can add something like <HttpErrorCodeReturnedEquals>404</HttpErrorCodeReturnedEquals>. And all requests should be 301.Aramaic
U
0

I fixed it by using HashRouter instead of Router

import { Switch, Route, HashRouter } from 'react-router-dom';

const App = () => (
    <HashRouter>
        <div>
            <NavBar/>
            <Switch>
                <Route exact path="/" component={Home}/>
                <Route exact path="/projects" component={Projects}/>
                <Route exact path="/about" component={About}/>
                <Route component={NoMatch}/>
            </Switch>
        </div>
    </HashRouter>
);

The app is acceccible by something like https://your-domain.s3.amazonaws.com/index.html?someParam=foo&otherPram=bar/#/projects

on localhost like https://localhost:3000/?someParam=foo&otherPram=bar/#/projects

No changes in S3 were needed.

Unni answered 20/10, 2020 at 9:16 Comment(1)
Looks like a quick and neat solution. But watch out! in their documentation they encourage to configure your server instead: "IMPORTANT NOTE: Hash history does not support location.key or location.state. In previous versions we attempted to shim the behavior but there were edge-cases we couldn’t solve. Any code or plugin that needs this behavior won’t work. As this technique is only intended to support legacy browsers, we encourage you to configure your server to work with <BrowserHistory> instead." reactrouter.com/web/api/HashRouterDegeneracy
R
0

I'm using NextJS and had the same issue. My solution was to check the routing information and push if it doesn't fit.

const router = useRouter();
useEffect(() => {
    if (!router.pathname.startsWith(router.asPath)) {
      router.push(router.asPath);
    }
  });

Nothing needed to be modified at the S3 side except from routing the error page to index.html

Repair answered 31/10, 2020 at 17:13 Comment(1)
so this worked while running your purely static Next.js app? In other words users would go to /projects which would let's say get you to index.html and then you'd find /projects because that was the router.asPath?Enolaenormity
D
0

In the latest version, Route is supposed to be the child of Routes, so we should wrap Route in Routes.

<Routes>
     <Route path="/home" element={<Home/>}
</Routes>
Demonstration answered 15/10, 2022 at 21:31 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.