我正在编写一个Web服务器,我需要在运行时注册处理程序.例如,"/ create"将为所有URL创建一个新的处理程序,如"/ 123/*"等.我需要一个相应的"/ destroy/123"来取消注册"/ 123/*"的处理程序.
这是处理"/ create"的代码
package main
import (
"fmt"
"net/http"
)
type MyHandler struct {
id int
}
func (hf *MyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
fmt.Fprintln(w, r.URL.Path)
}
// Creates MyHandler instances and registers them as handlers at runtime
type HandlerFactory struct {
handler_id int
}
func (hf *HandlerFactory) ServeHTTP(w http.ResponseWriter, r *http.Request) {
hf.handler_id++
handler := MyHandler{hf.handler_id}
handle := fmt.Sprintf("/%d/", hf.handler_id)
http.Handle(handle, &handler)
}
func main() {
factory := HandlerFactory{0}
http.Handle("/create", &factory)
http.ListenAndServe("localhost:8080", nil)
}
Run Code Online (Sandbox Code Playgroud)
我尝试通过嵌入实现我自己的多路复用器,http.ServeMux但它在私有变量(ServeMux.m)中保持其模式到处理程序的映射
Ste*_*erg 13
我要做的是创建一个自定义ServerMux.复制代码GOROOT/src/pkg/net/http/server.go.它从837行开始,到939结束.
自定义ServerMux需要一种取消注册的方法.这应该很容易实现.只需抓住锁和del()地图条目即可.例如(所有代码未经测试):
// TODO: check if registered and return error if not.
// TODO: possibly remove the automatic permanent link between /dir and /dir/.
func (mux *MyMux) Deregister(pattern string) error {
mux.mu.Lock()
defer mux.mu.Unlock()
del(mux.m, pattern)
return nil
}
Run Code Online (Sandbox Code Playgroud)
为了使用这个新的多路复用器,你可以这样做:
mux := newMux()
mux.Handle("/create", &factory)
srv := &http.Server {
Addr: localhost:8080
Handler: mux,
}
srv.ListenAndServe()
Run Code Online (Sandbox Code Playgroud)
通过deregister()从另一个goroutine 调用来修改mux 是完全安全的,并将修改ListenAndServe()路由消息的方式.
看来你已经接受了答案,但我想提出一个替代解决方案.
我怀疑是否需要添加自定义多路复用器.在这个例子中,我使用的是gorilla muxer,但这仅仅是因为我熟悉它的模式匹配.理论上,您可以匹配传入URL中的模式,而无需替换默认的muxer.
我的代码在map中维护处理函数(string:handler name => function literal)...这适用于使用默认的muxers HandleFunc方法.
样本输入/输出:
GET/register/123
GET/123
hello from123.
GET/destroy/123
GET/123
[nothing]
package main
import (
"code.google.com/p/gorilla/mux"
"flag"
"log"
"net/http"
)
// Wraps server muxer, dynamic map of handlers, and listen port.
type Server struct {
Dispatcher *mux.Router
Urls map[string]func(w http.ResponseWriter, r *http.Request)
Port string
}
// May the signal never stop.
func main() {
//Initialize Server
server := &Server{Port: "3000", Dispatcher: mux.NewRouter(), Urls: make(map[string]func(w http.ResponseWriter, r *http.Request))}
var port = flag.String("port", "3000", "Default: 3000; Set the port for the web-server to accept incoming requests")
flag.Parse()
server.Port = *port
log.Printf("Starting server on port: %s \n", server.Port)
server.InitDispatch()
log.Printf("Initializing request routes...\n")
server.Start() //Launch server; blocks goroutine.
}
func (s *Server) Start() {
http.ListenAndServe(":"+s.Port, s.Dispatcher)
}
// Initialize Dispatcher's routes.
func (s *Server) InitDispatch() {
d := s.Dispatcher
// Add handler to server's map.
d.HandleFunc("/register/{name}", func(w http.ResponseWriter, r *http.Request) {
//somewhere somehow you create the handler to be used; i'll just make an echohandler
vars := mux.Vars(r)
name := vars["name"]
s.AddFunction(w, r, name)
}).Methods("GET")
d.HandleFunc("/destroy/{name}", func(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
name := vars["name"]
s.Destroy(name)
}).Methods("GET")
d.HandleFunc("/{name}", func(w http.ResponseWriter, r *http.Request) {
//Lookup handler in map and call it, proxying this writer and request
vars := mux.Vars(r)
name := vars["name"]
s.ProxyCall(w, r, name)
}).Methods("GET")
}
func (s *Server) Destroy(fName string) {
s.Urls[fName] = nil //remove handler
}
func (s *Server) ProxyCall(w http.ResponseWriter, r *http.Request, fName string) {
if s.Urls[fName] != nil {
s.Urls[fName](w, r) //proxy the call
}
}
func (s *Server) AddFunction(w http.ResponseWriter, r *http.Request, fName string) {
f := func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("hello from" + fName))
}
s.Urls[fName] = f // Add the handler to our map
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5454 次 |
| 最近记录: |