diff --git a/commands/server.go b/commands/server.go index 602527253..7d604b97d 100644 --- a/commands/server.go +++ b/commands/server.go @@ -376,17 +376,36 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro } if redirect := f.c.serverConfig.MatchRedirect(requestURI); !redirect.IsZero() { + doRedirect := true // This matches Netlify's behaviour and is needed for SPA behaviour. // See https://docs.netlify.com/routing/redirects/rewrites-proxies/ - if redirect.Status == 200 { - if r2 := f.rewriteRequest(r, strings.TrimPrefix(redirect.To, u.Path)); r2 != nil { - requestURI = redirect.To - r = r2 + if !redirect.Force { + path := filepath.Clean(strings.TrimPrefix(requestURI, u.Path)) + fi, err := f.c.hugo().BaseFs.PublishFs.Stat(path) + if err == nil { + if fi.IsDir() { + // There will be overlapping directories, so we + // need to check for a file. + _, err = f.c.hugo().BaseFs.PublishFs.Stat(filepath.Join(path, "index.html")) + doRedirect = err != nil + } else { + doRedirect = false + } + + } + } + + if doRedirect { + if redirect.Status == 200 { + if r2 := f.rewriteRequest(r, strings.TrimPrefix(redirect.To, u.Path)); r2 != nil { + requestURI = redirect.To + r = r2 + } + } else { + w.Header().Set("Content-Type", "") + http.Redirect(w, r, redirect.To, redirect.Status) + return } - } else { - w.Header().Set("Content-Type", "") - http.Redirect(w, r, redirect.To, redirect.Status) - return } } @@ -416,7 +435,6 @@ func (f *fileServer) createEndpoint(i int) (*http.ServeMux, string, string, erro fileserver := decorate(http.FileServer(fs)) mu := http.NewServeMux() - if u.Path == "" || u.Path == "/" { mu.Handle("/", fileserver) } else { diff --git a/config/commonConfig.go b/config/commonConfig.go index ac82dc3bc..522ced854 100644 --- a/config/commonConfig.go +++ b/config/commonConfig.go @@ -184,6 +184,7 @@ type Redirect struct { From string To string Status int + Force bool } func (r Redirect) IsZero() bool { diff --git a/docs/content/en/getting-started/configuration.md b/docs/content/en/getting-started/configuration.md index 076d9161c..9cbe988f1 100644 --- a/docs/content/en/getting-started/configuration.md +++ b/docs/content/en/getting-started/configuration.md @@ -360,10 +360,10 @@ Note that a `status` code of 200 will trigger a [URL rewrite](https://docs.netli from = "/myspa/**" to = "/myspa/" status = 200 +force = false {{< /code-toggle >}} - - +{{< new-in "0.76.0" >}} Setting `force=true` will make a redirect even if there is existing content in the path. Note that before Hugo 0.76 `force` was the default behaviour, but this is inline with how Netlify does it. ## Configure Title Case