如何取消订阅http处理程序?

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

How can I unsubscribe http handler?

问题

我想创建一个HTTP处理程序来处理一个会话:

func init(){
    http.HandleFunc("/sess/215489598", func(w http.ResponseWriter, r *http.Request) {
	    //做一些事情
    })
}

然后在会话结束(过期)时将其删除。

我该如何做到这一点?

英文:

I want to create http handler to handle one session:

func init(){
    http.HandleFunc("/sess/215489598", func(w http.ResponseWriter, r *http.Request) {
	    //do something
    })
}

and then remove it when session ends(expires).

How can I do that ?

答案1

得分: 4

这是不直接可能的:HTTP多路复用器(ServeMux类型)不提供删除操作。

使用HTTP多路复用器进行会话管理被证明是一个不好的主意。当前的HTTP服务实现有点低效。它会为每个URL扫描整个多路复用器表,所以处理程序越多,性能就越差。对于一些路径来说还好,但是你无法以这种方式管理几百个会话,更不用说成千上万个了。

HTTP多路复用器需要一些同步机制才能用作会话管理工具。想象一下如果有一个Unhandle方法。如果你取消处理一个路径,你会期望多路复用器不再使用之前的数据处理你的路径。但是,不同的goroutine不能保证看到彼此对相同数据的更改,除非有某种同步机制。所以,HTTP处理程序仍然可以看到多路复用器的旧视图,然后使用你认为已经注销的处理程序来响应请求。

因此,HTTP处理程序本身不能为你做到这一点-也不应该这样做,因为你没有任何手段来同步会话的生命周期。

"/sess/"创建一个单一的处理程序。该处理程序应该负责委派给各个会话。它可以使用map[sessionID]sessionHandler来高效地完成这个任务,并且可以通过通道将所有会话管理传输给一个单独的goroutine来跟踪正在创建和销毁的会话,或者采用更传统的方法,在会话映射周围使用读写锁。这样,你可以确保在删除会话后不会尝试将新请求分派给会话处理程序。

当然,你可以随时收到一个HTTP请求,所以在你锁定映射以删除会话之前,有人可能会插入并连接到一个会话,如果在你决定锁定映射但实际上还没有锁定之前发生了上下文切换,所以请仔细管理你的锁和会话策略。在这里做的“正确的事情”主要取决于你个人应用的需求。

英文:

This isn't directly possible: an HTTP multiplexer (type ServeMux) does not expose a deletion operation.

Using an HTTP multiplexer for session management turns out to be a bad idea. The current implementation of HTTP serving is kind of inefficient. It scans the entire multiplexer table for each URL, so the more handlers you have, the worse performance gets. That's fine for a few paths, but you can't manage even a few hundred sessions that way, much less hundreds of thousands.

The HTTP multiplexer would need some kind of synchronization to be used as a session management tool. Imagine there was an Unhandle method. If you Unhandle a path, you would expect the multiplexer to no longer handle your path with its previous data. But, different goroutines aren't guaranteed to see each other's changes to the same data without some kind of synchronization. So, the HTTP handler could still see the old view of the multiplexer, then respond to the request using the handler you thought you deregistered.

So, the HTTP handler itself can't do this for you- nor should it, because you don't have any means to synchronize your session lifespan.

Create a single handler for "/sess/". That handler should be responsible for delegating to individual sessions. It can use a map[sessionID]sessionHandler to do this efficiently, and can either pipe all session management over channels to let a single goroutine keep track of sessions being created and destroyed, or go with a more traditional approach using reader-writer locks around your session map. This way, you can ensure that you won't try to dispatch a new request to a session handler after you've removed it.

Of course, you can get an HTTP request at any time, so someone might jump in and connect to a session the moment before you lock the map to delete the session, if a context switch happens in the instruction after you have decided you want to lock the map but before you actually do it, so manage your locks and session policies carefully. The "right thing" to do here depends mostly on the needs of your individual application.

答案2

得分: 3

I'm afraid golang http package hasn't implemented method to remove or modify http handler for now, read:

src/pkg/net/http/server.go

http://golang.org/src/pkg/net/http/server.go?s=28409:28496#L962

type ServeMux
func NewServeMux() *ServeMux
func (mux *ServeMux) Handle(pattern string, handler Handler)
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)

It just implemented register function HandleFunc().

You have 2 ways to work around:

1 Modify source code to implement an unregister function. This is not advisable, since using ServerMux directly is not a good idea.

Or:

2 Maybe you are make things much more complicated. You just need to parse /sess/215489598 in a general handler function, for example:

func Handler(response http.ResponseWriter, request *http.Request) {
  modules := strings.Split(request.URL.Path, "/")

  if modules[1] == "sess" {
    session_id := modules[2]
  }
}

Then you know how to do next 如何取消订阅http处理程序?

英文:

I'm afraid golang http package hasn't implemented method to remove or modify http handler for now, read:

src/pkg/net/http/server.go

http://golang.org/src/pkg/net/http/server.go?s=28409:28496#L962

type ServeMux
func NewServeMux() *ServeMux
func (mux *ServeMux) Handle(pattern string, handler Handler)
func (mux *ServeMux) HandleFunc(pattern string, handler func(ResponseWriter, *Request))
func (mux *ServeMux) ServeHTTP(w ResponseWriter, r *Request)

It just implemented register function HandleFunc().

You have 2 ways to work around:

1 Modify source code to implement an unregister function. This is not advisable, since using ServerMux directly is not a good idea.

Or:

2 Maybe you are make things much more complicated. You just need to parse /sess/215489598 in a general handler function, for example:

func Handler(response http.ResponseWriter, request *http.Request) {
  modules := strings.Split(request.URL.Path, "/")

  if modules[1] == "sess" {
    session_id := modules[2]
  }
}

Then you know how to do next 如何取消订阅http处理程序?

huangapple
  • 本文由 发表于 2013年4月10日 11:03:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/15916195.html
匿名

发表评论

匿名网友

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

确定