react router doesn't work in aws s3 bucket
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:
- 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.
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.
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.
- For
TypeScript
, currentlyreact-router
doesn't support it so you should consider option 2 and 3. They're going to update the library in future version6.*
according to this thread.
React-Router locations on AWS s3 bucket do not work
You have a couple of options.
Option #1:
The simplest is using HashRouter instead of BrowserRouter
. This will make changing paths look like http://<bucketname.s3-website-us-east-1.amazonaws.com#/Support
(note the #
). As the hash is only processed by the browser, it doesn't change the request path to the server. Note that this solves the problem for any static host, not just s3, so also works for e.g. github-pages.
Option #2:
If you don't want to have your paths like that, there is a mildly hacky solution. In the bucket settings under "Redirection Rules", you can add something like:
[
{
"Condition": {
"HttpErrorCodeReturnedEquals": "403"
},
"Redirect": {
"ReplaceKeyPrefixWith": "#/"
}
}
]
This says, "any time you get a request for a non-existent path, replace /path
with /#/path
. Now it's serving the main page with a hash parameter.
Finally, we want to remove the hash from the url, so in the root index.js
, BEFORE rendering the <App />
, you can do something like:
import { createBrowserHistory } from 'history'
const replaceHashPath = () => {
const history = createBrowserHistory()
const hash = history.location.hash
if (hash) {
const path = hash.replace(/^#/, '')
if (path) {
history.replace(path)
}
}
}
replaceHashPath()
This runs before anything is actually rendered, replaces the URL in the browser history with the non-hashed version, Now everything will work as expected.
Read more about redirection rules here: https://docs.aws.amazon.com/AmazonS3/latest/userguide/how-to-page-redirect.html
aws s3 404 error using react-router-dom (without cloudfront)
Disclaimer: this is a solution using CloudFront.
In case it might help.
I encountered similar problems when I used react-router-dom v5 & v6. I used BrowserRouter
. I deployed the React app directly to S3 without using AWS Amplify. I kept encountering 403 error instead of 404, although I rechecked all my permission settings.
This article helped me eventually: https://blog.nicera.in/2020/08/hosting-react-app-on-s3-cloudfront-with-react-router-404-fix/. And your questions raised here had been discussed and answered in details in this article.
Open up your CloudFront distribution for the React App. In the top tabs, click on Error Pages.
Add the configurations for 403 & 404 as below.
Related Topics
Jasmine: Async Callback Was Not Invoked Within Timeout Specified by Jasmine.Default_Timeout_Interval
About Closure, Lexicalenvironment and Gc
How to Set the Prototype of a JavaScript Object That Has Already Been Instantiated
Es6 Promise.All() Error Handle - Is .Settle() Needed
How to Get a JavaScript Object Property Name That Starts with a Number
Add Event Handler to HTML Element Using JavaScript
JavaScript Getelementbyid() Not Working
Dynamically Arrange Some Elements Around a Circle
Is There Any Difference Between Declared and Defined Variable
Finding Closest Element Without Jquery
JavaScript - Are Dom Redraw Methods Synchronous
Google Map API V3 - Set Bounds and Center
JavaScript Xmlhttprequest Using JSONp
Jquery - Get Text for Element Without Children Text
How to Convert String to Number According to Locale (Opposite of .Tolocalestring)
Calling Setstate in a Loop Only Updates State 1 Time