react router doesn't work in aws s3 bucket

2020-02-18 06:14发布

问题:

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>
);

回答1:

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.

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



回答2:

Answer to close the question. I've solved this issue thanks to Alan Friedman's comment above:

You need to redirect errors (404 in this case) to the root index.html – Jul 7 at 0:34



回答3:

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.



回答4:

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).



回答5:

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



回答6:

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.



回答7:

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.