donglao6169 2019-06-09 08:42
浏览 28
已采纳

Http.Server {}-多个处理程序?

I have a structural problem: I can't figure out how I can do with the way I built it up now (I can find solutions where i can see it work with other models ).

I'm using standard Net/Http, and I initiate my server with the following code :

gv := GlobalVars{
    jobs:             make(chan QueueElement),
    appConfig:        appConfig,
}

go worker(&gv)

server := http.Server{
    Handler: &gv,
    Addr:    ":" + appConfig.Port,
}

log.Fatal(server.ListenAndServe())

Then I have one handler that checks for all the routes in a case :

func (gv *GlobalVars) ServeHTTP(w http.ResponseWriter, r *http.Request) {

}

The application is starting up some api's that passes jobs to a queue.

My issue is, I need to start up 3 of these (different queues, different config ) but same globalvar structure.

But this one only has one Handler that i can set - how would I be add multiple handlers (I don't want multiple servers, has to run on the same port ) that can understand its addressing different globalvars variables ?

server := http.Server{
    Handler: &gv,
    Addr:    ":" + appConfig.Port,
}
  • 写回答

1条回答 默认 最新

  • doujia2386 2019-06-09 10:12
    关注

    Have a look at the net.http.ServeMux type:

    ServeMux is an HTTP request multiplexer. It matches the URL of each incoming request against a list of registered patterns and calls the handler for the pattern that most closely matches the URL.

    A ServeMux is itself an http.Handler and multiplexes to different subhandlers by request route. From what I understand of your question, you want to have different handlers on the same server, and each handler addresses a different queue with a different config.

    Using a ServeMux one can achieve that easily:

    gv1 := GlobalVars{
        jobs:             make(chan QueueElement),
        appConfig:        appConfig1,
    }
    gv2 := GlobalVars{
        jobs:             make(chan QueueElement),
        appConfig:        appConfig2,
    }
    gv3 := GlobalVars{
        jobs:             make(chan QueueElement),
        appConfig:        appConfig3,
    }
    
    sm := http.NewServeMux()
    // Let gv{1,2,3} handle routes{1,2,3} respectively
    sm.Handle("/route1", &gv1)
    sm.Handle("/route2", &gv2)
    sm.Handle("/route3", &gv3)
    
    // Register the ServeMux as the sole Handler. It will delegate to the subhandlers.
    server := http.Server{
        Handler: sm,
        Addr:    ":" + globalAppConfig.Port,
    }
    

    Note, you don't have to construct an http.Server by yourself. If you just need one server, you can use http package level functions http.ListenAndServe and http.Handle which take care of creating a Server and default ServeMux for you.

    // same GlobalVars as above
    // ...
    
    // Instead of creating a ServeMux we can use the global DefaultServeMux
    http.Handle("/route1", &gv1)
    http.Handle("/route2", &gv2)
    http.Handle("/route3", &gv3)
    
    // Calling the package level ListenAndServe uses the single global server.
    // Passing nil as the Handler uses the DefaultServeMux as Handler on which we registered the Handlers above.
    log.Fatal(http.ListenAndServe(":" + globalAppConfig.Port, nil)
    

    UPDATE

    A small example of the standard ServeMux with two Handlers serving 3 routes

    // Keeping this type simple for the example
    type GlobalVars struct {
        appConfig string
    }
    
    // This method makes every GlobalVars a net.http.Handler
    func (gv *GlobalVars) ServeHTTP(w http.ResponseWriter, req *http.Request) {
        fmt.Fprintf(w, "%s here. Receiving request for %s
    ", gv.appConfig, req.URL.Path)
    }
    
    func main() {
        gv1 := &GlobalVars{
            appConfig: "gv1",
        }
        gv2 := &GlobalVars{
            appConfig: "gv2",
        }
    
        // Handle requires a route and a Handler, our gvs are Handlers.
        // gv1 handles two routes, while gv2 handles only one.
        http.Handle("/route1", gv1)
        http.Handle("/route2", gv1)
        http.Handle("/route3", gv2)
    
        log.Fatal(http.ListenAndServe(":8000", nil))
    }
    

    If I call all three routes after one another, I will receive the following responses:

    $ curl localhost:8000/route1
    gv1 here. Receiving request for /route1
    $ curl localhost:8000/route2
    gv1 here. Receiving request for /route2
    $ curl localhost:8000/route3
    gv2 here. Receiving request for /route3
    

    This shows how to use stateful variables as Handlers (e.g. variables of type GlobalVars).

    NOTE: The handler method ServeHTTP has a pointer receiver for GlobalVars. This means the method could potentially change the GlobalVars variable. HTTP Handlers are executed concurrently (imagine multiple requests to the same handler in a very short time period, you'll want to stay as responsive as possible). This example only reads the appConfig value, so it's fine. Once a write to the variable/field comes into the mix, however, you'll need proper synchronization.

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥15 为什么使用javacv转封装rtsp为rtmp时出现如下问题:[h264 @ 000000004faf7500]no frame?
  • ¥15 乘性高斯噪声在深度学习网络中的应用
  • ¥15 运筹学排序问题中的在线排序
  • ¥15 关于docker部署flink集成hadoop的yarn,请教个问题 flink启动yarn-session.sh连不上hadoop,这个整了好几天一直不行,求帮忙看一下怎么解决
  • ¥30 求一段fortran代码用IVF编译运行的结果
  • ¥15 深度学习根据CNN网络模型,搭建BP模型并训练MNIST数据集
  • ¥15 C++ 头文件/宏冲突问题解决
  • ¥15 用comsol模拟大气湍流通过底部加热(温度不同)的腔体
  • ¥50 安卓adb backup备份子用户应用数据失败
  • ¥20 有人能用聚类分析帮我分析一下文本内容嘛