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

5

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

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

当会话结束(过期)时,需要将其删除。

我该怎么做?

2个回答

4

这是不可能直接实现的:HTTP多路复用器(ServeMux类型)没有暴露删除操作。

使用HTTP多路复用器进行会话管理最终证明是个坏主意。当前的HTTP服务实现相当低效。它为每个URL扫描整个多路复用器表格,所以处理程序越多,性能就越差。对于一些路径来说还好,但你不能以这种方式管理几百个甚至数十万个会话。

HTTP多路复用器需要某种同步才能用作会话管理工具。想象一下有一个Unhandle方法。如果你取消处理某个路径,你希望多路复用器不再使用其先前的数据处理该路径。但是,不同的goroutine在没有某种同步的情况下无法看到彼此对同一数据所做的更改。因此,HTTP处理程序仍然可以看到多路复用器的旧视图,然后使用你认为已经注销的处理程序响应请求。

因此,HTTP处理程序本身无法为您执行此操作,也不应该这样做,因为您没有任何手段来同步会话的生命周期。
创建一个"/sess/"的单个处理程序。 该处理程序应负责委派到各个会话。 它可以使用map [sessionID] sessionHandler来高效地执行此操作,并且可以通过管道将所有会话管理交给单个goroutine来跟踪被创建和销毁的会话,或者根据读写锁的传统方法使用会话映射。 这样,您可以确保在删除会话处理程序后不会尝试分派新请求到它。
当然,您可以随时收到HTTP请求,因此,如果在您决定要锁定映射但实际上未执行此操作的指令之后发生上下文切换,某人可能会在您锁定映射以删除会话之前的瞬间连接到会话。 因此,请仔细管理锁和会话策略。 在这里做“正确的事情”主要取决于您的个别应用程序的需求。

2
如果您使用Gorilla工具包,则不需要为每个请求扫描整个路由表。 - Rick-777

3
很抱歉,目前golang的http包还没有实现修改或移除http处理程序的方法,可以参考以下文件: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)

它只是实现了注册函数HandleFunc()

您有两种解决方法:

1 修改源代码以实现注销函数。这不是一个好主意,因为直接使用ServerMux不是一个好的选择。

或者:

2 也许你把事情弄得更加复杂了。你只需要在一个通用处理函数中解析/sess/215489598,例如:

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

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

那么你知道接下来该怎么做 :)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接