如何将两个(或多个)http.ServeMux组合在一起?

huangapple go评论85阅读模式
英文:

Go: How to combine two (or more) http.ServeMux?

问题

给定你有两个 http.ServeMux 的实例,并且你希望它们在相同的端口号上提供服务,像这样:

muxA, muxB http.ServeMux
// 初始化 muxA
// 初始化 muxB
combinedMux := combineMux([muxA, muxB])
http.ListenAndServe(":8080", combinedMux)

如何编写上述描述的 combinedMux 函数呢?

... 或者是否有其他方法可以实现相同的效果?

英文:

Given that you have two instances of http.ServeMux,
and you wish for them to be served at the same port number, like so:

    muxA, muxB http.ServeMux
    //initialise muxA
    //initialise muxB
    combinedMux := combineMux([muxA, muxB])
    http.ListenAndServe(":8080", combinedMux)

How would one go about writing the combinedMux function, as described above?

... or is there an alternative way to accomplish the same thing?

答案1

得分: 17

因为http.ServeMux也是一个http.Handler,所以你可以轻松地将一个mux嵌套在另一个mux中,即使它们在同一个端口和同一个主机名上。下面是一个示例:

rootMux := http.NewServeMux()
subMux := http.NewServeMux()

// 这将处理 /top_path/sub_path
subMux.HandleFunc("/sub_path", myHandleFunc)

// 使用 StripPrefix 确保 URL 已经映射到 subMux 可以读取的路径
rootMux.Handle("/top_path/", http.StripPrefix("/top_path", subMux))

http.ListenAndServe(":8000", rootMux)

请注意,如果没有http.StripPrefix()调用,你需要在较低级的mux中处理整个路径。

英文:

Because an http.ServeMux is also an http.Handler you can easily nest one mux inside another, even on the same port and same hostname. Here's one example of doing that:

rootMux := http.NewServeMux()
subMux := http.NewServeMux()

// This will end up handling /top_path/sub_path
subMux.HandleFunc("/sub_path", myHandleFunc)

// Use the StripPrefix here to make sure the URL has been mapped
// to a path the subMux can read
rootMux.Handle("/top_path/", http.StripPrefix("/top_path", subMux))

http.ListenAndServe(":8000", rootMux)

Note that without that http.StripPrefix() call, you would need to handle the
whole path in the lower mux.

答案2

得分: 3

SeverMux类型本身就是一个http.Handler,因此你可以轻松地嵌套它们。例如:

mux := NewServeMux()
mux.AddHandler("server1.com:8080/", muxA)
mux.AddHandler("server2.com:8080/", muxB)

我不太确定你所说的"combining"具体是什么意思。如果你想先尝试一个处理程序,然后在出现404的情况下再尝试另一个处理程序,你可以这样做(未经测试):

mux := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    rec := httptest.NewRecorder()
    rec.Body = &bytes.Buffer{}
    muxA.ServeHTTP(rec, r)
    if rec.Code == 404 {
        muxB.ServeHTTP(w, r)
        return
    }
    for key, val := range rec.HeaderMap {
        w.Header().Set(key, val)
    }
    w.WriteHeader(rec.Code)
    rec.Body.WriteTo(w)
})

这显然有一些缺点,比如将整个响应存储在内存中。或者,如果你不介意调用处理程序两次,你也可以设置rec.Body = nil,只检查rec.Code,并在成功的情况下再次调用muxA.ServeHTTP(w, r)。但是最好重新组织你的应用程序,使得第一种方法(嵌套的ServerMux)足够满足需求。

英文:

The SeverMux type is itself a http.Handler, therefore you can nest them easily. For example:

mux := NewServeMux()
mux.AddHandler("server1.com:8080/", muxA)
mux.AddHandler("server2.com:8080/", muxB)

I'm not quite sure what you mean exactly with "combining" them. If you want to try one handler first and then another one in case of 404, you might do it like this (untested):

mux := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    rec := httptest.NewRecorder()
    rec.Body = &bytes.Buffer{}
    muxA.ServeHTTP(rec, r)
    if rec.Code == 404 {
        muxB.ServeHTTP(w, r)
        return
    }
    for key, val := range rec.HeaderMap {
        w.Header().Set(key, val)
    }
    w.WriteHeader(rec.Code)
    rec.Body.WriteTo(w)
})

This has obviously some disadvantages like storing the whole response in memory. Alternatively, if you don't mind calling your handler twice, you can also set rec.Body = nil, check just rec.Code and call muxA.ServeHTTP(w, r) again in case of success. But it's probably better to restructure your application so that the first approach (nested ServerMux) is sufficient.

huangapple
  • 本文由 发表于 2014年5月16日 13:57:31
  • 转载请务必保留本文链接:https://go.coder-hub.com/23693520.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定