Изменение значения переменной внутри оператора if, ссылающегося на флаг

У меня есть следующая программа Go, которая представляет собой статический файловый сервер. Я получаю следующую ошибку в консоли:

..\static\main.go:45:5: cannot use handlers.CombinedLoggingHandler(os.Stdout, r) (type http.Handler) as type *mux.Router in assignment: need type assertion
..\static\main.go:52:5: cannot use handlers.CompressHandler(l) (type http.Handler) as type *mux.Router in assignment: need type assertion

Как я могу использовать флаги с маршрутизатором Gorilla Mux и CombinedLoggingHandler или CompressHandler?

package main

import (
    "flag"
    "fmt"
    "log"
    "net/http"
    "os"
    "time"

    "github.com/gorilla/handlers"
    "github.com/gorilla/mux"

    controllers "<this_is_a_local_repo>"
    common "<this_is_a_local_repo>"
)

var (
    host     = flag.String("host", "127.0.0.1", "TCP host to listen to")
    port     = flag.String("port", "8081", "TCP port to listen to")
    logging  = flag.Bool("logging", false, "Whether to enable HTTP response logging")
    compress = flag.Bool("compress", true, "Whether to enable transparent response compression")
    dir      = flag.String("dir", common.Abs("public"), "Directory to serve static files from")
)

func main() {
    flag.Parse()

    r := mux.NewRouter().StrictSlash(true)
    r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir(*dir))))
    r.PathPrefix("/").HandlerFunc(controllers.IndexHandler(*dir + "/index.html")) // catch-all route for 404

    l := r
    if *logging {
        l = handlers.CombinedLoggingHandler(os.Stdout, r)
    }

    h := l
    if *compress {
        h = handlers.CompressHandler(l) // gzip all responses
    }

    srv := &http.Server{
        Handler: h,
        Addr:    fmt.Sprintf("%s:%s", *host, *port),
        ReadTimeout:  5 * time.Second,
        WriteTimeout: 10 * time.Second,
        IdleTimeout:  15 * time.Second,
    }
    log.Fatal(srv.ListenAndServe())
}

person Lanti    schedule 16.03.2018    source источник
comment
var h http.Handler = r, если... то h = handlers.CombinedLoggingHandler(os.Stdout, h), если... то h = handlers.CompressHandler(h). Нет необходимости делать l := r и h := l, достаточно сделать h = middleware(h).   -  person mkopriva    schedule 17.03.2018
comment
вы назначаете *маршрутизатор для CombinedLoggingHandler и CompressHandler. Они оба требуют типа обработчика, что здесь не так.   -  person Himanshu    schedule 17.03.2018
comment
@Himanshu, ты имеешь в виду возврат, верно? Потому что, поскольку они принимают http.Handler в качестве аргумента, код в порядке, поскольку *mux.Router реализует этот интерфейс. Проблема в том, что они также возвращают http.Handler, но тип значения в левой части присваивания — *mux.Router, а не http.Handler... Проблема в том, какого типа эти две функции return, а не в том, что они требуют в качестве аргумента.   -  person mkopriva    schedule 17.03.2018
comment
Судя по первому комментарию, он должен это исправить play.golang.org/p/zD5Ran7t3Kj   -  person mkopriva    schedule 17.03.2018
comment
@mkopriva http.Handler — это функция, использующая servemux в качестве получателя. Вы объявили переменную этого типа. Хэндер - это тип? Я никогда не видел объявления переменной функционального типа. Пожалуйста, дополните. я в стадии обучения   -  person Himanshu    schedule 17.03.2018
comment
@Himanshu https://golang.org/pkg/net/http/#Handler не является функцией.   -  person mkopriva    schedule 17.03.2018
comment
Но если мы реализуем тип интерфейса, мы также должны реализовать его функцию. Я этого не видел. Итак, как обстоят дела. Пожалуйста, объясните.   -  person Himanshu    schedule 17.03.2018
comment
@Himanshu r относится к типу *mux.Router, этот тип уже реализует интерфейс http.Handler. Итак, var h http.Handler = r объявляет переменную h типа http.Handler и присваивает ей значение r, что правильно и будет компилироваться, потому что r (*mux.Router) имеет метод ServeHTTP, необходимый для реализации интерфейса.   -  person mkopriva    schedule 17.03.2018


Ответы (1)


Похоже, вы пытаетесь добавить промежуточное ПО на свой маршрутизатор gorilla/mux.

Вы можете добавить промежуточное ПО с помощью Router.Use().

Router.Use() принимает mux.MiddlewareFunc, которая представляет собой просто функцию с сигнатурой func (http.Handler) http.Handler. Большинство промежуточных программ, с которыми вы столкнетесь, соответствуют этой сигнатуре или могут быть легко обернуты для этого, как в примере ниже.

Сорвано из моего собственного внутреннего кода:

func myLoggingHandler(next http.Handler) http.Handler {
    return handlers.CombinedLoggingHandler(os.Stdout, next)
}

func main() {
    r := mux.NewRouter()

    if logging {
        r.Use(myLoggingHandler)
    }
    if compress {
        r.Use(handlers.CompressHandler)
    }

    http.Handle("/", r)

    log.Fatal(http.ListenAndServe("[::]:8009", nil))

}
person Michael Hampton    schedule 16.03.2018
comment
Я принимаю это как ответ, потому что это дает еще более простое решение моей проблемы, но я думаю, что решение mkopriva более универсально (для fasthttp). Я также заметил, что flag.Bool принимает каждый аргумент консоли как истинный, даже false, из-за отсутствия приведения типов. Поэтому я использую flag.String и if logging == "true" {}. - person Lanti; 17.03.2018
comment
Формат моих плохих логических флагов должен быть -foo=bar, извините. golang.org/pkg/flag - person Lanti; 17.03.2018