Remove the .html extension from every file in a simple HTTP server

人走茶凉 提交于 2019-12-24 04:18:26

问题


I want to make it so when someone visits a page on my Go HTTP server, they won't see the .html extension. E.g. when they visit https://example.org/test they will see the content of https://example.org/test.html.

My code:

package main

import (
    "net/http"
)

func main() {
    fs := http.FileServer(http.Dir("public/"))

    http.Handle("/", http.StripPrefix("/", fs))
    http.ListenAndServe(":8000", nil)
}

回答1:


One option is to implement http.FileSystem using http.Dir. The advantage of this approach is that it takes advantage of the carefully written code in http.FileServer.

It will look something like this:

type HTMLDir struct {
    d http.Dir
}

func main() {
  fs := http.FileServer(HTMLDir{http.Dir("public/")})
  http.Handle("/", http.StripPrefix("/", fs))
  http.ListenAndServe(":8000", nil)
}

The implementation of the Open method depends on the application requirements.

If you always want to tack on the .html extension, then use this code:

func (d HTMLDir) Open(name string) (http.File, error) {
    return d.d.Open(name + ".html")
}

If you want to fallback to the .html extension, then use this code:

func (d HTMLDir) Open(name string) (http.File, error) {
    // Try name as supplied
    f, err := d.d.Open(name)
    if os.IsNotExist(err) {
        // Not found, try with .html
        if f, err := d.d.Open(name + ".html"); err == nil {
            return f, nil
        }
    }
    return f, err
}

Flip the previous one around to start with the .html extension and fallback to the name as supplied:

func (d HTMLDir) Open(name string) (http.File, error) {
    // Try name with added extension
    f, err := d.d.Open(name + ".html")
    if os.IsNotExist(err) {
        // Not found, try again with name as supplied.
        if f, err := d.d.Open(name); err == nil {
            return f, nil
        }
    }
    return f, err
}



回答2:


It's possible, but it cannot be done by serving the files using http.FileServer().

Instead, create a custom handler for the / route. Inside the handler, serve the requested file directly using http.ServeFile().

viewPath := "public/"
http.Handle("/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

    // hack, if requested url is / then point towards /index
    if r.URL.Path == "/" {
        r.URL.Path = "/index"
    }

    requestedPath := strings.TrimLeft(filepath.Clean(r.URL.Path), "/")
    filename := fmt.Sprintf("%s/%s.html", viewPath, requestedPath)
    http.ServeFile(w, r, filename)
}))
http.ListenAndServe(":8000", nil)

The .html suffix is added to every request path, so it'll point correctly towards the html files.

path / -> ./public/index.html
path /index -> ./public/index.html
path /some/folder/about -> ./public/some/folder/about.html
...



回答3:


So basically you want the http.FileServer functionality, but you don't want clients having to enter the trailing .html extension.

Another simple solution is to add it yourself, at the server side. This is how it can be done:

fs := http.FileServer(http.Dir("public"))
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    r.URL.Path += ".html"
    fs.ServeHTTP(w, r)
})

panic(http.ListenAndServe(":8000", nil))

And that's all.

If you want this file server to also serve other files (such as images and CSS files), only append the .html extension if it has no extension:

http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
    if ext := path.Ext(r.URL.Path); ext == "" {
        r.URL.Path += ".html"
    }
    fs.ServeHTTP(w, r)
})


来源:https://stackoverflow.com/questions/57281010/remove-the-html-extension-from-every-file-in-a-simple-http-server

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!