2015-06-26 8 views
7

मैं गोलांग के लिए बिल्कुल नया हूं और इस मूर्खतापूर्वक करने के लिए सबसे अच्छा तरीका काम करने की कोशिश कर रहा हूं।गोरिल्ला मक्स को संदर्भ पास करना - मुहावरे

मेरे पास मार्गों की एक सरणी है जो मैं स्थिर रूप से परिभाषित कर रहा हूं और gorilla/mux पर जा रहा हूं। मैं प्रत्येक हैंडलर फ़ंक्शन को अनुरोध के समय और पैनिक्स को संभालने के साथ लपेट रहा हूं (मुख्य रूप से इसलिए मैं समझ सकता था कि रैपिंग कैसे काम करती है)।

मैं चाहता हूं कि वे प्रत्येक 'संदर्भ' तक पहुंच सकें - एक ऐसी संरचना जो एक-प्रति-http-server होने जा रही है, जिसमें डेटाबेस हैंडल, कॉन्फ़िगरेशन आदि जैसी चीज़ें हो सकती हैं। मैं क्या नहीं करता करना चाहते हैं एक स्थिर वैश्विक चर का उपयोग करें।

जिस तरह से मैं वर्तमान में इसे कर रहा हूं, मैं रैपर को संदर्भ संरचना तक पहुंच प्रदान कर सकता हूं, लेकिन मैं यह नहीं देख सकता कि इसे वास्तविक हैंडलर में कैसे प्राप्त किया जाए, क्योंकि यह http.HandlerFunc होना चाहता है। मैंने सोचा था कि क्या मैं अपने ही का एक प्रकार है कि Context के लिए एक रिसीवर था में http.HandlerFunc परिवर्तित किया जाता है कर सकता है (और रैपर के लिए इसी तरह करते हैं, लेकिन (ज्यादा के बाद के बारे में खेल रहे हैं) मैं नहीं तो यह स्वीकार करने के लिए Handler() मिल सकता है।

मैं मदद नहीं कर सकते लेकिन लगता है कि मैं यहाँ कुछ स्पष्ट याद कर रहा हूँ। नीचे कोड।

package main 

import (
    "fmt" 
    "github.com/gorilla/mux" 
    "html" 
    "log" 
    "net/http" 
    "time" 
) 

type Route struct { 
    Name  string 
    Method  string 
    Pattern  string 
    HandlerFunc http.HandlerFunc 
} 

type Context struct { 
    route *Route 
    // imagine other stuff here, like database handles, config etc. 
} 

type Routes []Route 

var routes = Routes{ 
    Route{ 
     "Index", 
     "GET", 
     "/", 
     index, 
    }, 
    // imagine lots more routes here 
} 

func wrapLogger(inner http.Handler, context *Context) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     start := time.Now() 

     inner.ServeHTTP(w, r) 

     log.Printf(
      "%s\t%s\t%s\t%s", 
      r.Method, 
      r.RequestURI, 
      context.route.Name, 
      time.Since(start), 
     ) 
    }) 
} 

func wrapPanic(inner http.Handler, context *Context) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
     defer func() { 
      if err := recover(); err != nil { 
       log.Printf("panic caught: %+v", err) 
       http.Error(w, http.StatusText(500), 500) 
      } 
     }() 

     inner.ServeHTTP(w, r) 
    }) 
} 

func newRouter() *mux.Router { 

    router := mux.NewRouter().StrictSlash(true) 
    for _, route := range routes { 
     // the context object is created here 
     context := Context { 
      &route, 
      // imagine more stuff here 
     } 
     router. 
      Methods(route.Method). 
      Path(route.Pattern). 
      Name(route.Name). 
      Handler(wrapLogger(wrapPanic(route.HandlerFunc, &context), &context)) 
    } 

    return router 
} 

func index(w http.ResponseWriter, r *http.Request) { 
    // I want this function to be able to have access to 'context' 
    fmt.Fprintf(w, "Hello, %q", html.EscapeString(r.URL.Path)) 
} 

func main() { 
    fmt.Print("Starting\n"); 
    router := newRouter() 
    log.Fatal(http.ListenAndServe("127.0.0.1:8080", router)) 
} 

यहाँ है एक तरह से यह करने के लिए है, लेकिन यह बहुत भयानक लगती है। मैं मदद नहीं कर सकता लेकिन लगता है कि होना चाहिए ऐसा करने के लिए कुछ बेहतर तरीका हो सकता है - शायद उपclass (?) http.Handler

package main 

import (
    "fmt" 
    "github.com/gorilla/mux" 
    "html" 
    "log" 
    "net/http" 
    "time" 
) 

type Route struct { 
    Name  string 
    Method  string 
    Pattern  string 
    HandlerFunc ContextHandlerFunc 
} 

type Context struct { 
    route *Route 
    secret string 
} 

type ContextHandlerFunc func(c *Context, w http.ResponseWriter, r *http.Request) 

type Routes []Route 

var routes = Routes{ 
    Route{ 
     "Index", 
     "GET", 
     "/", 
     index, 
    }, 
} 

func wrapLogger(inner ContextHandlerFunc) ContextHandlerFunc { 
    return func(c *Context, w http.ResponseWriter, r *http.Request) { 
     start := time.Now() 

     inner(c, w, r) 

     log.Printf(
      "%s\t%s\t%s\t%s", 
      r.Method, 
      r.RequestURI, 
      c.route.Name, 
      time.Since(start), 
     ) 
    } 
} 

func wrapPanic(inner ContextHandlerFunc) ContextHandlerFunc { 
    return func(c *Context, w http.ResponseWriter, r *http.Request) { 
     defer func() { 
      if err := recover(); err != nil { 
       log.Printf("panic caught: %+v", err) 
       http.Error(w, http.StatusText(500), 500) 
      } 
     }() 

     inner(c, w, r) 
    } 
} 

func newRouter() *mux.Router { 

    router := mux.NewRouter().StrictSlash(true) 
    for _, route := range routes { 
     context := Context{ 
      &route, 
      "test", 
     } 
     router.Methods(route.Method). 
      Path(route.Pattern). 
      Name(route.Name). 
      HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
      wrapLogger(wrapPanic(route.HandlerFunc))(&context, w, r) 
     }) 
    } 

    return router 
} 

func index(c *Context, w http.ResponseWriter, r *http.Request) { 
    fmt.Fprintf(w, "Hello, %q secret is %s\n", html.EscapeString(r.URL.Path), c.secret) 
} 

func main() { 
    fmt.Print("Starting\n") 
    router := newRouter() 
    log.Fatal(http.ListenAndServe("127.0.0.1:8080", router)) 
} 
+1

http://github.com/ पर एक नजर डालें एलेक्स्डवर्ड/स्टैक - यह मध्यवर्ती (हैंडलर) को ढेर करने के लिए एक आसान तरीका के साथ एक अच्छा सार प्रदान करता है श्रृंखला के माध्यम से एसएस संदर्भ। – Nadh

+0

गोरिल्ला के पास एक संदर्भ पैकेज है। – freeformz

+1

@ फ्रीफॉर्म गोरिल्ला का संदर्भ पैकेज प्रोग्राम संदर्भ के बजाय अनुरोध संदर्भ के लिए है। विशेष रूप से, यह अनुरोध के अंत में स्वचालित रूप से साफ़ हो जाता है (यदि आप गोरिल्ला/मक्स का उपयोग कर रहे हैं)। –

उत्तर

3

मैं एक लगभग समान समस्या के बीच में जाओ और वर्तमान में सीख रहा हूँ, और यह कैसे मैं इसके साथ निपटा है:


सबसे पहले, मुझे लगता है कि आप एक महत्वपूर्ण विस्तार याद किया: रहे हैं जाओ में कोई वैश्विक चर नहीं। widest scope you can have for a variable पैकेज स्कोप है। जाओ में ही सच्चा वैश्विक predeclared identifierstrue और false की तरह हैं (और आप इन बदलने के लिए या अपने खुद के बनाने के लिए नहीं कर सकते हैं)।

इसलिए, यह एक चर package main के दायरे वाला अपने कार्यक्रम के लिए संदर्भ धारण करने के लिए सेट करने के लिए पूरी तरह से ठीक है। एक सी/सी ++ पृष्ठभूमि से आ रहा है, यह मुझे उपयोग करने के लिए थोड़ा समय लगा। चूंकि वेरिएबल्स पैकेज स्कॉप्ड हैं, इसलिए वे the problems of global variables से पीड़ित नहीं हैं। अगर किसी अन्य पैकेज में कुछ ऐसी चर की आवश्यकता है, तो आपको इसे स्पष्ट रूप से पारित करना होगा।

जब यह समझ में आता है तो पैकेज चर का उपयोग करने से डरो मत। इसकी मदद से आप अपने कार्यक्रम में जटिलता को कम, और (जहां http.HandlerFunc() बुला और उत्तीर्ण कर लेना बंद करने के लिए पर्याप्त होगा) के मामलों का एक बहुत में अपने कस्टम संचालकों बहुत सरल बनाते हैं।

इस तरह के एक सरल हैंडलर इस प्रकार दिखाई देंगे:

func simpleHandler(c Context, next http.Handler) http.Handler { 
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 
    // FIXME Do something with our context 
    next.ServeHTTP(w, r) 
    }) 
} 

और द्वारा इस्तेमाल किया जा:

r = mux.NewRouter() 
http.Handle("/", simpleHandler(c, r)) 

अपनी आवश्यकताओं और अधिक जटिल हैं, तो आप अपने खुद के लागू करने के लिए आवश्यकता हो सकती है http.Handler । याद रखें कि http.Handler केवल एक इंटरफ़ेस है जो ServeHTTP(w http.ResponseWriter, r *http.Request) लागू करता है।

यह untested है, लेकिन आप वहाँ रास्ते से लगभग 95% मिलना चाहिए:

package main 

import (
    "net/http" 
) 

type complicatedHandler struct { 
    h http.Handler 
    opts ComplicatedOptions 
} 

type ComplicatedOptions struct { 
    // FIXME All of the variables you want to set for this handler 
} 

func (m complicatedHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { 
    // FIXME Do stuff before serving page 

    // Call the next handler 
    m.h.ServeHTTP(w, r) 

    // FIXME Do stuff after serving page 
} 

func ComplicatedHandler(o ComplicatedOptions) func(http.Handler) http.Handler { 
    return func(h http.Handler) http.Handler { 
     return complicatedHandler{h, o} 
    } 
} 

इसका इस्तेमाल करने के लिए: basicAuth in goji/httpauth देखना एक और अधिक विकसित हैंडलर उदाहरण के लिए

r := mux.NewRouter() 
// FIXME: Add routes to the mux 

opts := ComplicatedOptions{/* FIXME */} 
myHandler := ComplicatedHandler(opts) 

http.Handle("/", myHandler(r)) 

है, जो इस उदाहरण से बेकार ढंग से फट गया था।


कुछ आगे पढ़ने:

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