I have a Project in Flutter Web for which I'd like to create a landing page in pure HTML for SEO purposes. My intention is to create a Server that serves the static files with higher priority and if the static HTML files would return an error on the request, the built flutter web project should be used as fallback.
I created this server in Golang:
package main
import (
"net/http"
)
func main() {
http.ListenAndServe(":2000", professionalServer{})
}
type professionalServer struct{}
var flutterServer = http.FileServer(http.FileSystem(http.Dir("../../../professional/build/web")))
var staticServer = http.FileServer(http.FileSystem(http.Dir("../../../professional/landing-page/dist")))
func (professionalServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
res := preflightResponseWriter{OutputData: make(map[string]int)}
staticServer.ServeHTTP(res, r)
if res.OutputData["status_code"] == 200 {
staticServer.ServeHTTP(w, r)
} else {
flutterServer.ServeHTTP(w, r)
}
}
type preflightResponseWriter struct {
OutputData map[string]int
}
func (preflightResponseWriter) Header() http.Header {
return http.Header{}
}
func (preflightResponseWriter) Write([]byte) (int, error) {
return 0, nil
}
func (p preflightResponseWriter) WriteHeader(statusCode int) {
p.OutputData["status_code"] = statusCode
}
This would actually work, but the problem is that Flutter Web uses the hash format for routes (i.e. http://website.com/#/dashboard) and browser don't send the part that comes after the hashtag, so my golang server sees http://website.com/, then it checks if the static file server can handle this URL, which it can and so the static file server sends the response.
How can I fix this? Is it possible to send the full URL to the server, including the part that comes after #?
Thanks for your help in advance!
How I solved it inspired by the suggestion I got from @ResamVi: I followed the steps from the answer so that my app finally has the base href /app/.
Then, in order to make the server work properly, I did these changes to my server file:
package main
import (
"net/http"
"strings"
)
func main() {
http.ListenAndServe(":2000", professionalServer{})
}
type professionalServer struct{}
var flutterServer = http.StripPrefix("/app/", http.FileServer(http.FileSystem(http.Dir("../../../professional/build/web"))))
var staticServer = http.FileServer(http.FileSystem(http.Dir("../../../professional/landing-page/dist")))
func (professionalServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if strings.HasPrefix(r.URL.Path, "/app") {
rw := preflightResponseWriter{OutputData: make(map[string]int)}
flutterServer.ServeHTTP(rw, r)
if rw.OutputData["status_code"] >= 400 && rw.OutputData["status_code"] < 500 {
http.ServeFile(w, r, "../../../professional/build/web/index.html")
} else {
flutterServer.ServeHTTP(w, r)
}
} else {
staticServer.ServeHTTP(w, r)
}
// check if starts with /app
// if no -> staticServer
// if yes:
// simulate request, check if response code is ok
// if response code is ok, serve via flutterServer.Serve
// else serve file directly
}
type preflightResponseWriter struct {
OutputData map[string]int
}
func (preflightResponseWriter) Header() http.Header {
return http.Header{}
}
func (preflightResponseWriter) Write([]byte) (int, error) {
return 0, nil
}
func (p preflightResponseWriter) WriteHeader(statusCode int) {
p.OutputData["status_code"] = statusCode
}
Now, requests that start with /app will either load an asset for the flutter web app or, if there's no asset fulfilling the request, the index.html will be loaded. If the request URL doesn't start with /app, the static files are served.