2017-02-14 3 views
0

Моя основная main установка:контекст запроса устанавливается в NEGRONI промежуточного слоя теряется в гнездовой гориллы Subrouter

muxRouter := mux.NewRouter() 

v1Router.Router(muxRouter.PathPrefix("/v1").Subrouter()) 

http.Handle("/", muxRouter) 


n := negroni.Classic() 
n.Use(negroni.HandlerFunc(apiRouter.Middleware)) 
n.UseHandler(muxRouter) 

s := &http.Server{ 
    Addr:   ":6060", 
    Handler:  n, 
    ReadTimeout: 10 * time.Second, 
    WriteTimeout: 10 * time.Second, 
    MaxHeaderBytes: 1 << 20, 
} 
log.Fatal(s.ListenAndServe()) 

Внутри apiRouter.Middleware я задал следующий контекст:

context.Set(req, helperKeys.DomainName, "some-value") 

Однако в некоторых HandlerFunc в v1Router.Router при попытке установить Get значение контекста, результат равен нулю:

domain := context.Get(req, helperKeys.DomainName) 
fmt.Println("DomainName", domain) 

Печать: DomainName <nil>

Я знаю, что метод Set является правильным, как получить значения сразу после установки его в apiRouter.Middleware будет возвращать правильное значение строки.

ответ

0

Я закончил с использованием Go 1.7 «S построен в Context:

context.Set(req, helperKeys.DomainName, "some-value") 

// Replaced with: 

ctx := req.Context() 
ctx = context.WithValue(ctx, helperKeys.DomainName, "some-value") 
req = req.WithContext(ctx) 

И

domain := context.Get(req, helperKeys.DomainName) 

// Replaced with: 

domain := req.Context().Value(helperKeys.DomainName).(string) 
+0

Пожалуйста, используйте длинную версию преобразования типа '(домен, хорошо: = REQ .Context(). Value (...) ' Это сэкономит вам много головных болей, если есть проблема, такая как значение, которое никогда не будет установлено. Я бы также использовал пользовательские геттеры/сеттеры для значений контекста и неактивных ключей. из которых более безопасны на практике и не намного больше кода. – joncalhoun

0

На основании вашего ответа, он выглядит, как вы пытаетесь сохранить базу данных в контексте. Я бы не предложил сделать это. Вместо того, чтобы попробовать что-то вроде этого:

type Something struct { 
    DB *sql.DB // or some other DB object 
} 

func (s *Something) CreateUser(w http.ResponseWriter, r *http.Request) { 
    // use s.DB to access the database 
    fmt.Fprintln(w, "Created a user...") 
} 

func main() { 
    db := ... 
    s := Something{db} 
    http.HandleFunc("/", s.CreateUser) 
    // ... everything else is pretty much like normal. 
} 

Это дает ваши обработчики доступа к базе данных, не имея, чтобы установить его на контекст каждый раз. Значения контекста должны быть зарезервированы для вещей, которые вы не можете установить до выполнения. Например, идентификатор запроса, специфичный для этого веб-запроса. Вещи, которые переживают запрос, обычно не попадают в эту категорию, и ваше соединение с БД переведет запрос.

Если вы на самом деле нужны значение контекста, вы должны:

  1. Используйте методы получения и установки, которые набираются
  2. «пакетов должны определить ключи как неэкспортируемый типа, чтобы избежать столкновений.» - From the Go source code

Пример этого показан ниже, и я больше говорить о значениях контекста вообще в this blog post:

type userCtxKeyType string 

const userCtxKey userCtxKeyType = "user" 

func WithUser(ctx context.Context, user *User) context.Context { 
    return context.WithValue(ctx, userCtxKey, user) 
} 

func GetUser(ctx context.Context) *User { 
    user, ok := ctx.Value(userCtxKey).(*User) 
    if !ok { 
    // Log this issue 
    return nil 
    } 
    return user 
} 
+0

Эй, спасибо за головы, но я на самом деле не хранил БД, я просто стою g копия сеанса подключения к базе данных. Я подключаюсь к базе данных в основной функции и сохраняю только копию сеанса в контексте каждого запроса. – borislemke

+0

Это, как правило, нахмурило - копия соединения с БД совсем не специфична для этого запроса и может так же легко быть доступ через первый подход, который я показал здесь, что намного безопаснее в долгосрочной перспективе. Что может быть * больше kosher является сохранение сказать транзакции, созданные из соединения БД, и что транзакция будет жить только до тех пор, пока запрос будет жив. При этом я получаю желание сделать это, чтобы ускорить процесс. Я просто подумал, что дам вам знать, что есть лучшие способы справиться с этим, поскольку ваше приложение растет, что легче поддерживать и отлаживать. – joncalhoun

Смежные вопросы