Передача аргументов промежуточному программному обеспечению Negroni

Каждый запрос к моему приложению должен использовать какое-то промежуточное ПО. Используя документы Negroni, я реализовал это так:

func MyMiddleware(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
  // do some stuff before
  next(rw, r)
}

и в другом месте я использую:

n.Use(negroni.HandlerFunc(MyMiddleware))

Однако промежуточное программное обеспечение должно получить дополнительный аргумент, и я не уверен, как его встроить. На данный момент я просто устанавливаю значение как глобальную переменную, чтобы сделать его доступным, но я уверен, что есть более элегантный способ ?

Я хотел бы иметь возможность сделать что-то вроде этого:

n.Use(negroni.HandlerFunc(MyMiddleware(val)))

person tommyd456    schedule 26.08.2015    source источник


Ответы (1)


Лучшим способом было бы инкапсулировать промежуточное ПО как структуру, которая хранит свое состояние, а не просто функцию без состояния. (Вы также можете обернуть его как закрытие, но структура чище IMO):

type MyMiddleware struct {
    someval string
}

func NewMyMiddleware(someval string) *MyMiddleware {
    return &MyMiddleware{
       someval: someval,
    }
}


func (m *MyMiddleware) ServeHTTP(w http.ResponseWriter, r *http.Request, next http.HandlerFunc) {

    // Do Something with someval
    fmt.Println(m.someval)

    next(w, req)
}

и инициализировать его просто:

n.Use(NewMyMiddleware("foo"))

РЕДАКТИРОВАТЬ: Возможно, закрытие на самом деле было бы простым:

 someval := foo

 n.Use(negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
   // Do Something with someval
   fmt.Println(someval)

   next(w, req)
}))

Или у вас может быть функция, которая возвращает функцию промежуточного программного обеспечения:

func NewMiddleware(someval string) negroni.HandlerFunc {
     return negroni.HandlerFunc(func(rw http.ResponseWriter, r *http.Request, next http.HandlerFunc) {
       // Do Something with someval
       fmt.Println(someval)

       next(w, req)
    })
}

а потом

n.Use(NewMiddleware("foo"))
person Not_a_Golfer    schedule 26.08.2015
comment
Хммм - мне это кажется излишним - если честно, можно придерживаться глобальной переменной. - person tommyd456; 26.08.2015
comment
@tommyd456, пока вам не понадобится более одной переменной с состоянием или вам не понадобится более одного экземпляра вашего промежуточного программного обеспечения. Если это не так, то закрытия будет достаточно. Я добавлю это к своему ответу. - person Not_a_Golfer; 26.08.2015
comment
Мне нравится подход к закрытию - я сам попробовал и почти у цели. Спасибо за это. Утром попробую! - person tommyd456; 26.08.2015
comment
@tommyd456 Если вы используете глобальную переменную, убедитесь, что у вас нет гонок за данные (попробуйте Детектор гонок). Вы, вероятно, обнаружите, что добавление синхронизации для устранения гонок данных (часто/обычно) требует больше работы. - person Dave C; 26.08.2015
comment
@DaveC верно, если только это не какое-то неизменное состояние, такое как структура конфигурации, которую вы инициализируете в main () или что-то в этом роде. Обычно я использую замыкания, если постоянное состояние мало, и структуры, если оно есть, особенно если оно изменчиво. - person Not_a_Golfer; 26.08.2015