2012-07-31 14 views
5

मैं एक वेब सर्वर लिख रहा हूं जिसमें मुझे रनटाइम पर हैंडलर पंजीकृत करने की आवश्यकता है। जैसे "/ create" सभी यूआरएल जैसे "/ 123/*" और इसी तरह के लिए एक नया हैंडलर बनाएगा। मुझे एक संबंधित "/ नष्ट/123" की आवश्यकता है जो "/ 123/*" के लिए हैंडलर को अनधिकृत करेगा।मैं नेट/http में हैंडलर को अपंजीकृत कैसे करूं?

यहाँ से निपटने के लिए कोड है

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) 
} 

मैं http.ServeMux एम्बेड करके अपने खुद के बहुसंकेतक को लागू करने की कोशिश की "/ बनाने" लेकिन यह एक निजी चर (ServeMux.m)

उत्तर

13

मैं क्या करूँगा एक कस्टम ServerMux बनाएँ। कोड को GOROOT/src/pkg/net/http/server.go से कॉपी करें। यह लाइन 837 पर शुरू होता है और 9 3 9 पर समाप्त होता है।

कस्टम सर्वरमक्स को पंजीकरण के लिए एक विधि की आवश्यकता होगी। इसे लागू करना आसान होना चाहिए। बस लॉक और 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 
} 

आदेश इस नए mux का उपयोग करने के लिए आपको कुछ इस तरह करना होगा: एक और goroutine से deregister() फोन करके

mux := newMux() 
mux.Handle("/create", &factory) 

srv := &http.Server { 
    Addr: localhost:8080 
    Handler: mux, 
} 
srv.ListenAndServe() 

mux संशोधित करना पूरी तरह से सुरक्षित है और होगा मार्ग ListenAndServe() रूट संदेशों को संशोधित करें।

0

में अपनी पद्धति करने वाली हैंडलर मैपिंग रखती है हो सकता है कि एक हैंडलर को कुछ भी लौटाकर (ResponseWriter को कुछ भी नहीं लिखना) या एक 'नहीं मिला' प्रतिक्रिया उत्पन्न करने के द्वारा पंजीकरण रद्द कर दिया जा सके। पहले से पंजीकृत हैंडलर के पंजीकरण के लिए आपकी आवश्यकताओं और/या उद्देश्य/प्रभाव पर निर्भर करता है।

+2

चिंता यह है कि हैंडलर रजिस्ट्री समय के साथ बढ़ रही है रखने के लिए और तेजी से महंगा हैंडलर लुकअप की वजह से अनुरोध बदलाव में एक मंदी का कारण बन जाएगा। –

6

ऐसा लगता है कि आप पहले ही एक उत्तर स्वीकार कर चुके हैं, लेकिन मैं वैकल्पिक समाधान का प्रस्ताव देना चाहता था।

मैं कस्टम मक्सर जोड़ने की आवश्यकता पर सवाल उठाता हूं। इस उदाहरण में मैं गोरिल्ला मक्सर का उपयोग कर रहा हूं, हालांकि यह केवल इसलिए है क्योंकि मैं इसके पैटर्न मिलान से परिचित हूं। सिद्धांत रूप में आप डिफ़ॉल्ट मक्सर को बदलने की आवश्यकता के बिना आने वाले यूआरएल से पैटर्न से मेल खा सकते हैं।

मेरे कोड एक नक्शे में हैंडलर कार्यों को बनाए रखता है (स्ट्रिंग: हैंडलर नाम => समारोह शाब्दिक) ... यह डिफ़ॉल्ट muxers HandleFunc विधि का उपयोग के लिए उपयुक्त है।

नमूना इनपुट/आउटपुट:

प्राप्त/रजिस्टर/123

प्राप्त/123
hello from123.

प्राप्त/नष्ट/123

प्राप्त/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 
} 
+0

आपका समाधान बहुत अच्छा है। यह संभवतः मैंने किया होगा यदि मूल यूआरएल संरचना व्याख्या मानक पुस्तकालय का हिस्सा थी। मेरी आवश्यकता वर्तमान में एक नया पैकेज लाने के लिए पर्याप्त जटिल नहीं है, लेकिन मुझे संदेह है कि ऐसा होने के लिए बहुत अधिक पुनरावृत्ति नहीं होगी और मैं उस समय गोरिल्ला के लिए जा सकता हूं। –

संबंधित मुद्दे