паника: последний аргумент должен иметь тип http.HandlerFunc - PullRequest
0 голосов
/ 20 декабря 2018

У меня есть эта вспомогательная функция, которая прекрасно компилируется:

func Middleware(adapters ...interface{}) http.HandlerFunc {

    log.Info("length of adapters:", len(adapters))

    if len(adapters) < 1 {
        panic("Adapters need to have length > 0.");
    }

    h, ok := (adapters[len(adapters)-1]).(http.HandlerFunc)

    if ok == false {
        panic("Last argument needs to be of type http.HandlerFunc") // ERROR HERE
    }

    adapters = adapters[:len(adapters)-1]

    for _, adapt := range adapters {
        h = (adapt.(AdapterFunc))(h)
    }

    return h

}

Я называю это так:

router.HandleFunc("/share", h.makeGetMany(v)).Methods("GET")

func (h Handler) makeGetMany(v Injection) http.HandlerFunc {
    return mw.Middleware(
        mw.Allow("admin"),
        func(w http.ResponseWriter, r *http.Request) {
            log.Println("now we are sending response.");
            json.NewEncoder(w).Encode(v.Share)
        },
    )
}

проблема в том, что я получаю эту ошибку, и яне могу понять, почему:

    panic: Last argument needs to be of type http.HandlerFunc

    goroutine 1 [running]:
    huru/mw.Middleware(0xc420083d40, 0x2, 0x2, 0xc42011f3c0)
            /home/oleg/codes/huru/api/src/huru/mw/middleware.go:301 +0x187
    huru/routes/share.Handler.makeGetMany(0xc4200ae1e0, 0x10)
            /home/oleg/codes/huru/api/src/huru/routes/share/share.go:62 +0x108

подтверждает, что длина среза адаптеров равна 2:

 length of adapters:2

Кто-нибудь знает, почему утверждение типа не будет выполненов этом случае?Не имеет смысла.Может быть, я не получаю последний аргумент фрагмента или что-то еще?Есть ли лучший способ вытолкнуть последний аргумент из фрагмента?

Ответы [ 2 ]

0 голосов
/ 21 декабря 2018

В пакете http ListenAndServe имеет следующую подпись

func ListenAndServe(addr string, handler Handler) error

, где Handler (т.е. http.Handler) - это интерфейс

type Handler interface {
    ServeHTTP(ResponseWriter, *Request)
}

Для одного веб-приложения существует только один вызов ListenAndServe, то есть только один handler, который должен работать со всеми точками доступа, такими как /url1, /url2 и т. Д. Если мы напишем handler с нуля, реализация может быть пользовательской struct, которая обхватывает дескриптор базы данных.Его метод ServeHTTP проверяет точку доступа и записывает соответствующий контент в ResponseWriter, что довольно утомительно и смешанно.

Это мотивация ServeMux , то есть router в вашем коде.Он имеет метод ServeHTTP , поэтому он удовлетворяет интерфейсу http.Handler и может использоваться для ListenAndServe.Кроме того, он имеет метод HandleFunc для работы с отдельной точкой доступа

func (mux *ServeMux) HandleFunc(pattern string,
                                handler func(ResponseWriter, *Request))

Обратите внимание, что handler не является http.Handler, т. Е. У него нет метода ServeHTTP,В этом нет необходимости, поскольку mux уже имеет ServeHTTP, а его метод ServeHTTP может отправлять запрос отдельной точки доступа соответствующим обработчикам.

Обратите внимание, что у него также есть метод Handle, который требует, чтобы аргумент удовлетворял интерфейсу http.Handler.Это немного менее удобно по сравнению с методом HandleFunc.

func (mux *ServeMux) Handle(pattern string, handler Handler)

Теперь вернемся к вашему вопросу, поскольку вы вызываете router.HandleFunc, его ввод не обязательно должен быть http.Handler.Поэтому альтернативным решением является использование func(ResponseWriter, *Request) в качестве типа возврата для промежуточного программного обеспечения и makeGetMany метода.(утверждение типа в промежуточном программном обеспечении также должно быть обновлено, возможно, нужно обновить гораздо больше кода)

@ xpare решение состоит в том, чтобы выполнить преобразование типа так, чтобы все сигнатуры функций совпадали, т.е.конвертировать func(ResponseWriter, *Request) в http.HandlerFunc.Также интересно посмотреть, как это работает.Из реализации

// The HandlerFunc type is an adapter to allow the use of
// ordinary functions as HTTP handlers. If f is a function
// with the appropriate signature, HandlerFunc(f) is a
// Handler that calls f.
type HandlerFunc func(ResponseWriter, *Request)

// ServeHTTP calls f(w, r).
func (f HandlerFunc) ServeHTTP(w ResponseWriter, r *Request) {
    f(w, r)
}

вы можете видеть, что он в основном определяет метод ServeHTTP для вызова самого себя.

0 голосов
/ 20 декабря 2018

Вам необходимо заключить 2-й аргумент оператора mw.Middleware() в тип http.Handler, используя http.HandlerFunc().

func (h Handler) makeGetMany(v Injection) http.HandlerFunc {
    return mw.Middleware(
        mw.Allow("admin"),
        http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            log.Println("now we are sending response.");
            json.NewEncoder(w).Encode(v.Share)
        }),
    )
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...