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 2020长安杯与连接网探
  • ¥15 关于#matlab#的问题:在模糊控制器中选出线路信息,在simulink中根据线路信息生成速度时间目标曲线(初速度为20m/s,15秒后减为0的速度时间图像)我想问线路信息是什么
  • ¥15 banner广告展示设置多少时间不怎么会消耗用户价值
  • ¥16 mybatis的代理对象无法通过@Autowired装填
  • ¥15 可见光定位matlab仿真
  • ¥15 arduino 四自由度机械臂
  • ¥15 wordpress 产品图片 GIF 没法显示
  • ¥15 求三国群英传pl国战时间的修改方法
  • ¥15 matlab代码代写,需写出详细代码,代价私
  • ¥15 ROS系统搭建请教(跨境电商用途)