doujiufutaog59220 2017-07-02 02:49
浏览 111
已采纳

如何使用Go服务动态创建的URL路径?

I am using react-router and browserHistory's pushState in a reactjs project. This project lets a user create a note which creates a new path. To serve this type of site I need to serve the same HTML file to every path besides the static content. So my nodejs code looks like this.

// Serve the static content
app.use('/static/css/', express.static(path.join(__dirname, '../../react-ui/build/static/css')));
app.use('/static/js/', express.static(path.join(__dirname, '../../react-ui/build/static/js')));
app.use('/static/media/', express.static(path.join(__dirname, '../../react-ui/build/static/media')));
app.use('/static/img/', express.static(path.join(__dirname, '../../react-ui/build/static/img')));
app.use('/img/', express.static(path.join(__dirname, '../../react-ui/build/img')));

// Serve the same HTML file to everything else
app.use('*', express.static(path.join(__dirname, '../../react-ui/build'))); 

I don't see any wildcard support for the Go FileServer. Currently I have all the static pages served using Go code similar to this.

package main

import (
    "net/http"
)

func init(){
    fs := http.FileServer(http.Dir("web"))
    http.Handle("/", fs)
    http.Handle("/static-page-1/", http.StripPrefix("/static-page-1/", fs))
    http.Handle("/static-page-2/", http.StripPrefix("/static-page-2/", fs))
    http.Handle("/static-page-3/", http.StripPrefix("/static-page-3/", fs))
}

Is it possible to serve content to dynamically generated URL paths with a Go server?

If the Handle method supported variables then I'd write the code like this

fs := http.FileServer(http.Dir("web"))
http.Handle("/static/", fs)
http.Handle("/{unknownUserPath}", http.StripPrefix("/{unknownUserPath}", fs))

{unknownUserPath} would be any path that a user types in that is not under /static/ path.

Here's the go project structure

enter image description here

Here's the server based on @putu answer

package main

import (
    "net/http"
    "strings"
)

func adaptFileServer(fs http.Handler) http.Handler {
    fn := func(w http.ResponseWriter, req *http.Request) {
        staticIndex := strings.Index(req.URL.Path, "/static/");
        imgIndex := strings.Index(req.URL.Path, "/img/");

        if staticIndex == -1 && imgIndex == -1 {
            fsHandler := http.StripPrefix(req.URL.Path, fs)
            fsHandler.ServeHTTP(w, req)
        } else {
            fs.ServeHTTP(w, req)
        }
    }
    return http.HandlerFunc(fn)
}

func init() {
    fs := http.FileServer(http.Dir("web"))
    http.Handle("/", adaptFileServer(fs))
}
  • 写回答

3条回答 默认 最新

  • dotif64826 2017-07-02 04:44
    关注

    If you want to serve static contents with URL pattern /* to a specific directory, then use the answer provided by jeevatkm.

    If you need slightly customizable version, you need a kind of adapter that map the URL path to static file handler (http.FileServer). The example code looks like:

    package main
    
    import (
        "log"
        "net/http"
        "regexp"
    )
    
    func helloHandler(w http.ResponseWriter, r *http.Request) {
        w.Write([]byte("Hello world!"))
    }
    
    func adaptFileServer(fs http.Handler, mux http.Handler) http.Handler {
        fn := func(w http.ResponseWriter, req *http.Request) {
            //Use your Path matcher here.
            //For demonstration, REGEX match is used
            //and it's probably not the most efficient.
            staticRegex := regexp.MustCompile("^/static-page-[0-9]+/")
            if matches := staticRegex.FindStringSubmatch(req.URL.Path); matches != nil {
                log.Printf("Match: %v, %v", req.URL.Path, matches[0])
                fsHandler := http.StripPrefix(matches[0], fs)
                fsHandler.ServeHTTP(w, req)
            } else if mux != nil {
                log.Printf("Doesn't match, pass to other MUX: %v", req.URL.Path)
                mux.ServeHTTP(w, req)
            } else {
                http.Error(w, "Page Not Found", http.StatusNotFound)
            }
        }
        return http.HandlerFunc(fn)
    }
    
    func init() {
        //Usual routing definition with MUX
        mux := http.NewServeMux()
        mux.HandleFunc("/hello", helloHandler)
    
        //"Dynamic" static file server.
        fs := http.FileServer(http.Dir("web"))
        http.Handle("/", adaptFileServer(fs, mux))
    }
    
    func main() {
        log.Fatal(http.ListenAndServe(":8080", nil))
    }
    

    In the above adapter example, if request path match to a specific pattern (/static-page-*/ in the above example), it will be passed to http.FileServer. If doesn't match, and if a multiplexer is specified, it will call mux.ServeHTTP. Otherwise it will return 404 error.

    If you want another matching rule, just change the regex pattern (or use your custom matcher).

    Note:
    Please don't use a same handler instance for FileServer and mux. For example, when you call http.Handle, it use http.DefaultServeMux to handle routing. If you pass http.DefaultServeMux as the second argument of adaptFileServer you may end up with endless recursion.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(2条)

报告相同问题?

悬赏问题

  • ¥15 oracle集群安装出bug
  • ¥15 关于#python#的问题:自动化测试
  • ¥20 问题请教!vue项目关于Nginx配置nonce安全策略的问题
  • ¥15 教务系统账号被盗号如何追溯设备
  • ¥20 delta降尺度方法,未来数据怎么降尺度
  • ¥15 c# 使用NPOI快速将datatable数据导入excel中指定sheet,要求快速高效
  • ¥15 再不同版本的系统上,TCP传输速度不一致
  • ¥15 高德地图点聚合中Marker的位置无法实时更新
  • ¥15 DIFY API Endpoint 问题。
  • ¥20 sub地址DHCP问题