Currently I am serving my react app using the following setup
func main() {
http.Handle("/", http.FileServer(http.Dir("./build/")))
http.HandleFunc("/my_api", handler)
http.ListenAndServe(":8090", nil)
}
and frontend
function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/my_frontend_path">MyPath</Link>
</li>
</ul>
</nav>
<Switch>
<Route path="/my_frontend_path">
<MyPath />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
But when I directly access http://localhost:8090/my_frontend_path
from the browser golang returns 404 page not found
, is there a way to delegate any path not supported in main
to default to frontend react router?
The issue you are experiencing is covered in some detail in the answers to this question. Its worth reading through the answers (particularly the accepted one) because there are a range of options (with varying downsides).
The basic issue is that when you make the initial request to http://localhost:8090/my_frontend_path
your frontend react router is not running so the browser requests the page from the server; as my_frontend_path
does not exist in the build
folder http.FileServer
returns a 404 page not found
error.
I suspect that the simplest solution for you may be to use hash history (covered in the accepted answer).
However as you have provided some Go server side code there is a fairly simple, purely server side, option. The "Catch-all" approach works by returning index.html
(and hence your app) for any path that is not handled elsewhere. This means that your application will be loaded and the router should detect the my_frontend_path
and act accordingly (this is why the contents of index.html
is returned rather than a redirect). One way of implementing this simply is:
const FSPATH = "./build/"
func main() {
fs := http.FileServer(http.Dir(FSPATH))
http.HandleFunc("/my_api", func(w http.ResponseWriter, _ *http.Request) { w.Write([]byte("API CALL")) })
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
// If the requested file exists then return if; otherwise return index.html (fileserver default page)
if r.URL.Path != "/" {
fullPath := FSPATH + strings.TrimPrefix(path.Clean(r.URL.Path), "/")
_, err := os.Stat(fullPath)
if err != nil {
if !os.IsNotExist(err) {
panic(err)
}
// Requested file does not exist so we return the default (resolves to index.html)
r.URL.Path = "/"
}
}
fs.ServeHTTP(w, r)
})
http.ListenAndServe(":8090", nil)
}
As written this will return the contents of index.html
if the file does not exist - this includes files like favicon.ico
. If this is an issue you may want to add some limits (e.g. check the extension).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With