
ã³ã³ããã¹ããšã¯äœã§ããïŒ
äž»ãªè³ªåããå§ããŸããã-ããã¯ã©ã®ãããªæŠå¿µããã³ã³ããã¹ããã§ããïŒ ãã®ã³ã³ããã¹ãã¯ãããŒãããžãŒã«ç³ãèš³ãããŸããããã³ã³ããã¹ãã¯APIé¢æ°ã®å¢çéã§éä¿¡ããããªããžã§ã¯ãã«é¢ããæ å ±ã§ãã éåžžããªããžã§ã¯ãã¯ãããã¯ãŒã¯ãªã¯ãšã¹ããæå³ããAPIã®å¢çã¯ç°ãªãããã«ãŠã§ã¢ãç°ãªãããã±ãŒãžãæœè±¡åã®å±€ãæå³ããŸããããã³ã³ããã¹ããã®æŠå¿µã¯ãããã¯ãŒã¯ãªã¯ãšã¹ãã ãã«åºæã®ãã®ã§ã¯ãããŸããã ãã ãããã®èšäºã§ã¯äž»ã«ãããã«ã€ããŠèª¬æããŸãã
å žåçãªäŸã¯ãJWTããŒã¯ã³ãããŠãŒã¶ãŒæ å ±ãæœåºãããã®æ å ±ããã³ãã©ãŒã«æž¡ããŠãã¢ã¯ã»ã¹ã®ç¢ºèªããã°ãžã®æžã蟌ã¿ãªã©ãè¡ãããšã§ãã
ãã®ã³ã³ããã¹ãã®æŠå¿µã¯ãå°ãªããšããããã¯ãŒã¯ã¯ãšãªã§ã¯ãå€ãã®èšèªãšãã¬ãŒã ã¯ãŒã¯ã§å©çšå¯èœã§ã-CïŒã§ã¯HttpContext ãJava Netty ã§ã¯-ChannelHandlerContext ãPython Twisted ã§ã¯-twisted.python.contextãªã©ã
ã³ã³ããã¹ãã移å
Goæšæºã©ã€ãã©ãªã«ã¯åªããHTTPã¹ã¿ãã¯ãããã ã10Kæ¥ç¶ã®åé¡ããæããããšãªããã«ãã¹ã¬ãããµãŒããŒããã°ããäœæãã Handlerã€ã³ã¿ãŒãã§ã€ã¹ã䜿çšããŠããŸããŸãªãªã¯ãšã¹ãåŠçã¹ã¯ãªãããç°¡åã«å®è£ ã§ããŸãã ãã ããæšæºã©ã€ãã©ãªã«ã¯httpãã³ãã©ãŒã®ã³ã³ããã¹ãã¯ãããŸããã
ããããGoã¯ãã¡ã€ã³ã®æšæºã©ã€ãã©ãªã«å ããŠãGoã®èè ãããã¡ã€ã³ã®Goã³ãŒãã®å€éšã§éçºãããæšæºã©ã€ãã©ãªã®ããã«äžäœäºææ§ã®ããŒãçŽæãæããªãããã±ãŒãžã®å¥åã®ã°ã«ãŒããæã£ãŠããŸãã ãããã¯ãã¹ãŠgolang / x /ã«ããããã±ãŒãžã§ãã ãã®äžã§ããé·ãéãã³ã³ããã¹ãã®æ¬è³ªãå®è£ ããããã/ã³ã³ããã¹ãããã±ãŒãžããããããã«ã€ããŠã¯æ¬æ¥ã話ãããŸãã å·çæç¹ã§ã¯ã GoDocã«ãããš ããã®ããã±ãŒãžã¯1560ããã±ãŒãžã§ãã§ã«äœ¿çšãããŠããŸãã
äžéšã«ã¯ãæšæºã©ã€ãã©ãªã«ã³ã³ããã¹ãããªããããWebãã¬ãŒã ã¯ãŒã¯ã®åç©åå šäœãåºçŸãããããããç¬èªã®æ¹æ³ã§ãªã¯ãšã¹ãã³ã³ããã¹ããéä¿¡ããåé¡ã解決ããŸããã
Zooãã¬ãŒã ã¯ãŒã¯
ãzooããšããèšèã䜿ããšãç¹ã«åé¡ã¯ãªãã®ã§ãå°ãèªåŒµããŸãã æšæºã®net / httpã¯åºç€ãšããŠã¯è¯ãã§ãããäœããã®WebãµãŒãã¹ã®èšè¿°ãéå§ãããšããã«ãããé«åºŠãªæ©èœïŒã°ã«ãŒãåãé«åºŠãªãã®ã³ã°ãæ¿èªåŠçãã¢ã¯ã»ã¹å¶åŸ¡ãªã©ã®è€éãªã«ãŒãã£ã³ã°ïŒãå®è£ ããå¿ èŠãçããŸãããããŠããã¯åœç¶äžçš®ã®ãã¬ãŒã ã¯ãŒã¯ã«å€ãããŸã-å€ãã®äººã¯ãã£ãšåãæ©èœãå¿ èŠãšããåãã¢ãããŒãã圌ãã®å¥œã¿ã«ãªããŸãã ããããå šäœãšããŠãéåžžãæã人æ°ã®ãããã¬ãŒã ã¯ãŒã¯ãããã€ãããããããã¯æã å€æŽããããŒãã¡ã¢ãªã®å²ãåœãŠãšé床ã§ç«¶åããŸã ã ä»ã人æ°ã®ã€ã·ã¯ã ãžã³ãŽããã¯ã®ãããªãã®ã§ã ã
åãã¬ãŒã ã¯ãŒã¯ã¯ãç¬èªã®æ¹æ³ã§ã³ã³ããã¹ããæž¡ãåé¡ã«åãçµã¿ãŸããã GorillaToolkitã¯ãåèŠæ±ã®å€ã®ã°ããŒãã«ããããä¿æããmutexã§èŠæ±ãä¿è·ããŸãã Gojiãšãã®ä»ã®ãŠãŒã¶ãŒã¯ããªã¯ãšã¹ãããšã«åå¥ã®ããããä¿æããŠããŸãã gocraft / webã¯ããªãã¬ã¯ã·ã§ã³ãéããŠã³ã³ââããã¹ããåŠçããŸãã åè¿°ã®Gin- Contextã¯ãäžè¬çã«ãã¹ãŠã®ãã³ãã©ãŒãæ©èœããããŒæ§é ã§ãã ãšã³ãŒã§ã¯ãã³ã³ããã¹ãã®æŠå¿µã¯äžè¬ã«ããªã¯ãšã¹ãåŠçã®ãã¹ãŠã®æ©èœã«ããã£ãŠããŸãã
ãããã®ã¢ãããŒãã«ã¯ããããé·æãšçæããããŸããããã¹ãŠã«ãã€ãã¹ã®1ã€ããããŸã-ãã¬ãŒã ã¯ãŒã¯ãžã®ãã€ã³ãã§ãã äžã§è¿°ã¹ãããã«ãã³ã³ããã¹ãã¯ããªãæœè±¡çãªæŠå¿µã§ãããhttp-requestã«éå®ãããŸããã ãããäŸã§èŠãŠã¿ãŸãããã
äŸ
ç°¡åãªWebãµãŒãã¹ããå§ããŸãããã
package main import ( "net/http" ) func handler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World")) } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":1234", nil) }
$ curl http://localhost:1234 Hello World
ããããããã§ã¯ãPINã³ãŒãã«ããããªããã£ããªæ¿èªãå¿ èŠã§ãããhttp.HandlerFuncã䜿çšããŠç°¡åãªããã«ãŠã§ã¢ãäœæããŸãã
func needPin(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { if r.FormValue("pin") != "9999" { http.Error(w, "wrong pin", http.StatusForbidden) return } h(w, r) } } ... http.HandleFunc("/", needPin(handler)) ...
$ curl http://localhost:1234 wrong pin $ curl http://localhost:1234?pin=9999 Hello World
ãã°ãããã§ãããããŒãã³ãŒãã§ã¯ãªããSQLããŒã¿ããŒã¹ãããã³ãèªã¿åãå¿ èŠããããŸãã OKãä»ã®ãšããã* sql.DBã°ããŒãã«å€æ°ãè¿œå ããŸãã
func needPin(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var pin string if err := db.QueryRow("SELECT pin FROM pins").Scan(&pin); err != nil { http.Error(w, "database error", http.StatusInternalServerError) return } ...
ã³ãŒãå
šäœ
$ sqlite3 pins.db SQLite version 3.8.4.3 2014-04-03 16:53:12 Enter ".help" for usage hints. sqlite> CREATE TABLE pins(pin STRING); sqlite> INSERT INTO pins(pin) VALUES ("9999"); sqlite> ^D
package main import ( "database/sql" _ "github.com/mattn/go-sqlite3" "net/http" ) var ( db *sql.DB err error ) func handler(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Hello World")) } func needPin(h http.HandlerFunc) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var pin string if err := db.QueryRow("SELECT pin FROM pins").Scan(&pin); err != nil { http.Error(w, "database error", http.StatusInternalServerError) return } if r.FormValue("pin") != pin { http.Error(w, "wrong pin", http.StatusForbidden) return } h(w, r) } } func main() { if db, err = sql.Open("sqlite3", "./pins.db"); err != nil { panic(err) } defer db.Close() http.HandleFunc("/", needPin(handler)) http.ListenAndServe(":1234", nil) }
ãããŠãç§ãã¡ã®èŠä»¶ãšæ¬²æã®ãªã¹ãã倧ãããªãå§ããŸãã
- ééã£ãPINã³ãŒãã§åãªã¯ãšã¹ããsyslogã«èšé²ããããšã¯å¯èœã§ããïŒ
- ãã ããIPã¢ãã¬ã¹ã確èªããŠèšé²ããããšã¯ã§ããŸããïŒ
- ããããç°ãªãIPã«å¯ŸããŠã·ã£ãŒãã£ã³ã°ãå®è¡ããç°ãªãããŒã¿ããŒã¹ã§å®è¡ã§ããŸããïŒ
- ã§ããŸãã...ïŒ
ããã¡ããã§ããŸããæ°ããã¿ã¹ã¯ããšã«ããã«ãŠã§ã¢ãèããŠèšè¿°ãããããããã§ãŒã³ã§çµã¿ç«ãŠå§ããŸãã Aliceãªã©ããã®ããã®åå¥ã®ããã±ãŒãžããããŸãã ããããauthMiddlewareããlogMiddlewareã«èªèšŒãšã©ãŒãæž¡ãæ¹æ³ã¯ïŒ ãŸããäžæçãªãã¹ã¯ãŒãã®ããã«Vaultã§å®è¡ããå¿ èŠãããå Žåãæåã«ã»ãã·ã§ã³ããããŒã¯ã³ãæœåºããŸããïŒ ããããã°ããŒãã«å€æ°ãåãé€ããããŒã¿ããŒã¹æ¥ç¶ãªããžã§ã¯ãããã³ãã©ãŒã«æž¡ãæ¹æ³ã¯ïŒ
ããã§ãã³ã³ããã¹ãã®æŠå¿µã圹ç«ã¡ãŸãã åããã«ãŠã§ã¢é¢æ°ã¯ããã®å€ãã³ã³ããã¹ãå€æ°ã«èšå®ãããªã¯ãšã¹ããšã³ã³ããã¹ããããã«æž¡ããŸãã èš±å¯ã¹ããŒã¿ã¹ããŠãŒã¶ãŒåãã¢ã¯ã»ã¹èš±å¯ãåæãªã¯ãšã¹ãã®ããããŒããååŸããæ å ±ãããŒã¿ããŒã¹æ¥ç¶ãžã®ãã€ã³ã¿ãŒãããã«è¿œè·¡ããããã®äžæã®IDãªã©ããã®ã³ã³ããã¹ãã«èªç±ã«å ¥åã§ããŸãã
éåžžãcontext.Contextã¯ãã©ã¡ãŒã¿ãŒãšããŠé¢æ°ã«æž¡ãããŸãïŒããã«ãŠã§ã¢ãšèŠæ±ã§æ©èœããé¢æ°ã®äž¡æ¹ïŒã ååãšããŠãã³ã³ããã¹ããæ§é äœãã£ãŒã«ããšããŠä¿åã§ããŸãããã³ã³ããã¹ãã¯ãªã¯ãšã¹ãã«çµã³ä»ããããå¿ èŠããããããããã¯æ éã«è¡ãå¿ èŠããããŸãããªã¯ãšã¹ãããšã«äœæããããªã¯ãšã¹ãã®åŠçåŸã«åé€ãããŸãã
ãããã ããã/ã³ã³ããã¹ãã¯å€ãä¿åããã ãã§ãªããã¿ã€ã ã¢ãŠãã管çããŠãªã¯ãšã¹ãããã£ã³ã»ã«ããããã®çµ±äžãããã¢ãããŒãã§ããããŸãã ãã£ãšè©³ããèŠãŠã¿ãŸãããã
å åŽããã®ããã/ã³ã³ããã¹ã
ããã/ã³ã³ããã¹ãAPIã¯å°ãçããã®ã§ãæåã¯é©ããããããŸããã
ããã§ã¯ãGoã§è€éãªãªã¯ãšã¹ãåŠçãã€ãã©ã€ã³ãéåžžã©ã®ããã«äœæãããããç解ããããšãéèŠã§ããããã¯éåžžã1ã€ã®ãªã¯ãšã¹ããåãå ¥ãããŽã«ãŒãã³ã§ããã®ãªã¯ãšã¹ããŸãã¯ãªã¯ãšã¹ãã®ã¹ããªãŒã ãåŠçãã1ã€ä»¥äžã®ãŽã«ãŒãã³ãçæããçµæããããã«è¿ããŸãã ããã¯ãé¢æ°ã®åçŽãªåæåŒã³åºããšããŠãå Žåã«ãã£ãŠã¯åå¥ã®ããã±ãŒãžã«ééã空ãããããã£ãã«ãéä¿¡ããæ°ãããŽã«ãŒãã³ãšãã£ãã«ã®ã«ã¹ã±ãŒãå šäœãšããŠå®è¡ã§ããŸãã äž»ãªãã®ã¯ãåããã«ãŠã§ã¢ãåããã±ãŒãžã®è²¬ä»»ã®æ確ãªå¢çãããããããããèŠæ±ã«ã€ããŠäœããç¥ãããããããŠããã«ã€ããŠäœããããããšããããšã§ãã
ãããã£ãŠãããã/ã³ã³ããã¹ãã®æåã®äž»èŠãªååã¯ã ã³ã³ããã¹ãããã¹ããã ãããªãŒæ§é ãæã£ãŠãããšããããšã§ãã å®éãnet / contextããã±ãŒãžã®äž»ãªæ©èœã¯ãããè¡ããŸãã æ¢åã®ã³ã³ããã¹ãããæ°ããã³ã³ããã¹ãã®ããªãšãŒã·ã§ã³ãäœæããæ°ããããµãã³ã³ããã¹ãããçæããŸãã
func Background() Context func TODO() Context func WithCancel(parent Context) (ctx Context, cancel CancelFunc) func WithDeadline(parent Context, deadline time.Time) (Context, CancelFunc) func WithTimeout(parent Context, timeout time.Duration) (Context, CancelFunc) func WithValue(parent Context, key interface{}, val interface{}) Context
2çªç®ã®éèŠãªç¹ã¯ãcontext.Contextãã€ã³ã¿ãŒãã§ãŒã¹ã§ãããnet / contextããã±ãŒãžãæäŸããããªãšãŒã·ã§ã³ã¯ãããã§ããããè€éãªã³ã³ããã¹ããèªç±ã«äœæã§ããããšã§ãã
type Context interface { Deadline() (deadline time.Time, ok bool) Done() <-chan struct{} Err() error Value(key interface{}) interface{} }
æ¢åã®ã³ã³ããã¹ãã®äž»ãªã¿ã€ããèŠãŠã¿ãŸãããã
- context.BackgroundïŒïŒã¯ç©ºã®ã³ã³ããã¹ãã§ãããå€ãã¿ã€ã ã¢ãŠãããã£ã³ã»ã«ããããŸããã éåžžãBackgroundïŒïŒã¯ãæåã«çä¿¡èŠæ±ãåä¿¡ããé¢æ°ã§äœ¿çšãããåŸç¶ã®ãã¹ãŠã®æŽŸçèŠæ±ã®åºç€ãšãªããŸãã
camilstoreã®äŸã次ã«ç€ºããŸãã
client := oauth2.NewClient(context.Background(), google.ComputeTokenSource(""))
- context.TODOïŒïŒãç¹å¥ãªã³ã³ããã¹ãã§ããã空ã§ããã䜿çšããã³ã³ããã¹ããæ確ã§ãªãå ŽåããŸãã¯ã³ã³ããã¹ããåãå ¥ããããã«é¢æ°ããŸã ãªãã¡ã¯ã¿ãªã³ã°ãããŠããªãå Žåã«äœ¿çšãããŸãã éçã³ãŒãã¢ãã©ã€ã¶ãŒããã®ã±ãŒã¹ãç°¡åã«èŠã€ããããããã«ãTODOåãç¹ã«éžæãããŸããã ãã ããçŸæç¹ã§ã¯ãã³ã³ããã¹ããåæãããªã³ã¿ãŒã¯ãŸã ãªãŒãã³ãœãŒã¹ã§ã¯ãããŸããããGoogleäžã«ãããä»åŸããªãŒãã³ã«ãªãäºå®ã§ãã
- context.WithCancelïŒèŠªã³ã³ããã¹ãïŒïŒctxã³ã³ããã¹ããCancelFuncã®ãã£ã³ã»ã«ïŒ -æ°ããDoneãã£ãã«ãšãã®ãã£ãã«ã®ã¯ããŒãºãéå§ããCancelFuncé¢æ°ãå«ã芪ã³ã³ããã¹ãã®ã³ããŒãè¿ããŸãã
ä»çµã¿ãèŠãŠã¿ãŸãããã
func handler(w http.ResponseWriter, r *http.Request) { // ctx, cancel = context.WithCancel(context.Background()) defer cancel() // Done, go func() { time.Sleep(1 * time.Second) ctx.Done <- struct{}{} }() // res, err:= startLongQuery(ctx, w) if err != nil { http.Error(w, "cancelled", http.StatusInternalError) return } // ...encode res to json w.Write(encodedResult) } func startLongQuery(ctx context.Context, w http.ResponseWriter) (*Result, error) { resCh, transport := runLongQueryToJavaService(someArgs) select { case <-ctx.Done(): // transport.CancelRequest(req) <-resCh return nil, ctx.Err() case result := <-resCh: // , Done, return Result{result}, nil } }
ãã®äŸã¯æå³çã«ç°¡ç¥åãããŠãããã¿ã€ã ã¢ãŠãã«ã³ã³ããã¹ãã䜿çšããæ¹æ³ã¯ä»¥äžã§èª¬æããŸãããèãæ¹ã¯æ確ã§ããå¿ èŠããããŸãã
匷å¶ãã£ã³ã»ã«ã¯ãããšãã°ãç°ãªããµãŒãã¹ã¬ããªã«ãžã®åæãªã¯ãšã¹ãã®å Žåã«äŸ¿å©ã§ããæéã®ã¬ããªã«ã®å¿çåŸãæ®ãã®ãªã¯ãšã¹ãã¯ãªãœãŒã¹ãç¡é§ã«ãªããªãããã«å®å šã«ãã£ã³ã»ã«ã§ããŸãã - context.WithTimeoutïŒèŠªContextãã¿ã€ã ã¢ãŠãtime.DurationïŒïŒContextãCancelFuncïŒããã³context.WithDeadlineïŒèŠªContextãdeadline time.TimeïŒïŒContextãCancelFuncïŒ -WithCancelïŒïŒã«äŒŒãŠããŸãããã¿ã€ã ã¢ãŠããŸãã¯éæåŸã«çµäºããŸãç· ãåãã å®éãWithTimeoutã¯ããã©ã¡ãŒã¿ãŒtime.NowïŒïŒãAddïŒtimeoutïŒãæã€WithDeadlineã§ãã
WithCancelã®ä»çµã¿ãç解ããŠããã°ãããã2ã€ã®æ©èœã«åé¡ã¯ãªãã¯ãã§ãã äžèšã®äŸã¯æ°è¡ç°¡ç¥åãããŠããã次ã®ãããªããšãã§ããŸãã
timeout, err := time.ParseDuration(req.FormValue("timeout")) if err == nil { ctx, cancel = context.WithTimeout(context.Background(), timeout) }
é·ããªã¯ãšã¹ããåŸ ã€æéã瀺ããŸãã - context.WithValueïŒèŠªã³ã³ããã¹ããããŒã€ã³ã¿ãŒãã§ã€ã¹{}ãvalã€ã³ã¿ãŒãã§ã€ã¹{}ïŒã³ã³ããã¹ã -äžèšã®ã³ã³ããã¹ãã«é¢é£ããããŒã¿ãŸãã¯ãªãœãŒã¹ãä¿åããã¿ã¹ã¯ã«äœ¿çšãããŸã
context.WithValueã«ã€ããŠããå°ã
äžèšã®ãã¬ãŒã ã¯ãŒã¯ãšã¯ç°ãªããããã/ã³ã³ããã¹ãã¯ãããªãŒããŒã¹ã®ãã¹ããããã¢ãŒããã¯ãã£ã®ãããããããŸãã¯åæ§ã®ããŒã¿æ§é ã䜿çšããŸããã 1ã€ã®ã³ã³ããã¹ãã«ã¯ã1ã€ã®å€ãšèŠªã³ã³ããã¹ããå«ãŸããŸãã æ°ããæå³-ããã¯ãã§ã«æ°ããã³ã³ããã¹ãã§ãã ããŒãšæå³èªäœã®äž¡æ¹ã¯ãã©ã®ã¿ã€ãã§ãããŸããŸããã
ããã䜿çšããããã®æšæºçãªã¡ã«ããºã ã¯æ¬¡ã®ãšããã§ããããŒã¯ãã³ã³ããã¹ãã§åäœã§ããä»ã®ããã±ãŒãž/ APIãšã®è¡çªãé¿ããããã«ããšã¯ã¹ããŒãäžå¯èœãªã¿ã€ãã§ãªããã°ãªããŸããã äŸïŒ
package userIP // , type key int // IP . - , . const userIPKey key = 0
å€èªäœã®ã³ã³ããã¹ãã¯æ¬¡ã®ããã«ãªããŸãïŒhttps://github.com/golang/net/blob/master/context/context.go#L433ïŒïŒ
type valueCtx struct { Context key, val interface{} } // Value func (c *valueCtx) Value(key interface{}) interface{} { if c.key == key { return c.val } return c.Context.Value(key) }
ã芧ã®ãšãããä»»æã®ã³ã³ããã¹ãã®å ¥ãåã䜿çšããŠãValueïŒïŒã¯ãç®çã®åã®ç®çã®å€ãèŠã€ãããŸã§ã³ã³ããã¹ãããªãŒãäžã«ç§»åããŸãã ãŸãããŸãã¯ãnilãè¿ãã®ã¯ãValueïŒïŒããã¹ãŠã®ã³ã³ããã¹ãã«å¯ŸããŠå®çŸ©ãããŠããããã§ãïŒèŠããŠããããã«ãContextã¯ã€ã³ã¿ãŒãã§ã€ã¹ã§ããããããã£ãŠãBackgroundã³ã³ããã¹ãã«å¯ŸããŠãå®çŸ©ãããŠããŸãïŒã
ã³ã³ããã¹ãå€ã§æ©èœãããµã³ãã«ããã±ãŒãžã®å®å šãªã³ãŒãã¯ã次ã®ããã«ãªããŸãã
å®å
šãªã³ãŒã
// Package userip provides functions for extracting a user IP address from a // request and associating it with a Context. package userip import ( "fmt" "net" "net/http" "golang.org/x/net/context" ) // FromRequest extracts the user IP address from req, if present. func FromRequest(req *http.Request) (net.IP, error) { ip, _, err := net.SplitHostPort(req.RemoteAddr) if err != nil { return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr) } userIP := net.ParseIP(ip) if userIP == nil { return nil, fmt.Errorf("userip: %q is not IP:port", req.RemoteAddr) } return userIP, nil } // The key type is unexported to prevent collisions with context keys defined in // other packages. type key int // userIPkey is the context key for the user IP address. Its value of zero is // arbitrary. If this package defined other context keys, they would have // different integer values. const userIPKey key = 0 // NewContext returns a new Context carrying userIP. func NewContext(ctx context.Context, userIP net.IP) context.Context { return context.WithValue(ctx, userIPKey, userIP) } // FromContext extracts the user IP address from ctx, if present. func FromContext(ctx context.Context) (net.IP, bool) { // ctx.Value returns nil if ctx has no value for the key; // the net.IP type assertion returns ok=false for nil. userIP, ok := ctx.Value(userIPKey).(net.IP) return userIP, ok }
äœãã©ã®ããã«ã³ã³ããã¹ãã«å ¥ãããã¯ãç¹å®ã®ã¿ã¹ã¯ã«äŸåããŸãã åçŽãªãŠãŒã¶ãŒIDãå éšã«å€ãã®æ å ±ãå«ãè€éãªæ§é ããŸãã¯ããŒã¿ããŒã¹ãæäœããããã®sql.DBã®ãããªãªããžã§ã¯ãã®ããããã§ãã
ãã³
ã³ã³ããã¹ãããŠãããŒãµã«ã€ã³ã¿ãŒãã§ã€ã¹ãšããŠå®è£ ãããšãä»ã®ãã¬ãŒã ã¯ãŒã¯ã®ã³ã³ããã¹ãã䜿çšããã³ãŒããnet / contextã䜿çšããã³ãŒããšãã¬ã³ãã«ãªããŸãã
gorilla / contextã䜿çšããã³ã³ããã¹ãã®äŸïŒ blog.golang.org/context/gorilla/gorilla.go
ãããŠããããå¥ã®ãã¬ãŒã ã¯ãŒã¯ã§ããtombã§ãªã¯ãšã¹ãããã£ã³ã»ã«ããäŸã®äŸã§ãïŒ blog.golang.org/context/tomb/tomb.go
ãŸãã¯ãDapperã¹ã¿ã€ã«ã§ãªã¯ãšã¹ãã®å¯¿åœã远跡ããããã«ã³ã³ããã¹ãã䜿çšããäŸãšããŠã net / traceããã±ãŒãžã 芪ã³ã³ããã¹ãã¯context.WithValueïŒctxãtraceïŒãçæãããªã¯ãšã¹ãã®åŠçäžã«çæããããã¹ãŠã®åŸç¶ã®åŒã³åºããšã³ã³ããã¹ãã«ã¯ãã¬ãŒã¹IDãå«ãŸããæ¢ã«ããã/ãã¬ãŒã¹ã³ãŒãã«ã¯WebããŒãžã®ãã¬ãŒã¹ã«é¢ããæ å ±ãæäŸããå¿ èŠãªãã³ãã©ãŒãå«ãŸããŠããŸããã¹/ debug / requestsããã³/ debug / events ã
æããã«ãæ倧ã®å©ç¹ã¯ãå€éšãªãœãŒã¹ãšéä¿¡ããããæ°ãããŽã«ãŒãã³ãçæãããã¹ãŠã®ã³ãŒããããã/ã³ã³ããã¹ãã䜿çšããå Žåã§ãã ããšãã°ãGoã®Googleã³ãŒãããŒã¹ã¯æ¢ã«çŽ1,000äžè¡ã®ã³ãŒããæã£ãŠããŸãããã©ãã§ãcontext.Contextã䜿çšããŠããŸãã Protobuf3ã®æ°ããgPC RPCãã¬ãŒã ã¯ãŒã¯ã¯ãGoã®ã³ãŒããçæãããšãã«ãã©ãã§ãcontext.Contextãæž¡ããŸãã
ä»åŸã®èšç»
ããã/ã³ã³ããã¹ãã®å°æ¥ã®èšç»ã«ã€ããŠæŽ»çºãªè°è«ããããGo 1.7ã®æšæºã©ã€ãã©ãªã«ã³ã³ããã¹ãã衚瀺ãããå¯èœæ§ããããŸãã ããããå°ããªå€æŽãããããããããªããããããŸãããããããã«ãããèå³ãšæ¬²æ±ãããã®ã§ãããªãã¯æãèæã€ã¹ãã§ãã
æšæºã©ã€ãã©ãªã¯ããèªäœã§äžäœäºææ§ããããã³ãŒãããŒã¹ãæçåããªãããã«httpãšctxhttpã«åå²ãããããªããšã¯ãããŸããïŒ ctxhttpããã±ãŒãžã¯çŸåšå®éšãšããŠååšããŠããŸãïŒã Contextãã£ãŒã«ããhttp.Requestã«è¿œå ãããããä»ã®ãªãã·ã§ã³ã衚瀺ãããå¯èœæ§ããããŸãã
net / contextããã®netãšããåèªã¯æ¶ããå¯èœæ§ããããŸãã
åç §è³æ
ãã詳现ã«ç解ããäŸãåç §ãããå Žåã¯ã次ã®ãªã³ã¯ã匷ããå§ãããŸãã
Good Goããã°ã³ã³ããã¹ãèšäº-blog.golang.org/context
GothamGo 2014ã³ã³ããã¹ãã«é¢ããããŒã¯-vimeo.com/115309491
http.Handlerãšnet / contextã«é¢ããå¥ã®èšäºã¯joeshaw.org/net-context-and-http-handlerã§ã
ãããã¯ããã/ã³ã³ããã¹ãã«é¢ããåªããã¬ããŒãã®è©³çŽ°ãªã¹ã©ã€ã-go-talks.appspot.com/github.com/guregu/slides/kami/kami.slide#1
Goã®é«åºŠãªãã€ãã©ã€ã³ãšãã£ã³ã»ã«ã«é¢ããèšäº-blog.golang.org/pipelines
ããŸããŸãªãã¬ãŒã ã¯ãŒã¯ã§ã®ã³ã³ããã¹ãå®è£ ã®æŠèŠ-www.nicolasmerouze.com/share-values-between-middlewares-context-golang
ãœãŒã¹ã³ãŒãããã/ã³ã³ããã¹ã-github.com/golang/net/tree/master/context