• Как шарить экземпляр класса между http хендлерами используя контекст?

    @mantyr
    Пишу много Golang кода с удовольствием:)
    В https://golang.org/pkg/net/http/#Handler находим интерфейс Handler:

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


    Создаём реализацию:
    package handlers
    
    import (
            "project/context"
    )
    
    type AddItemsRequestData struct {
            Name string `json:"name"`
    }
    
    type AddItems {
            ctx *context.Context
    }
    
    func NewAddItems(ctx *context.Context) (*AddItems, error) {
            return &AddItems{
                    ctx: ctx,
            }, nil
    }
    
    func (h *AddItems) ServeHTTP(res http.ResponseWriter, req *http.Request) {
            ...
            h.ctx.Profiler.Get("name")   <-- здесь для каждого запроса пользователя вызывается метод Get() заранее инициализированного объекта
            ...
    }


    package main
    
    import (
            "log"
    
            "project/context"
            "project/handlers"
    )
    
    func main() {
            ...
            ctx, err := context.New()
            if err != nil {
                    log.Fatalf(err)
            }
            ...
            http.Handle("/profiler/", CheckHandler(handlers.NewAddItem(ctx)))
            ...
            err := http.ListenAndServe(":80", nil)
            log.Fatalf(err)
    }
    
    // CheckHandler проверяет создание хандлера
    func CheckHandler(handler http.Handler, err error) http.Handler {
            if err != nil {
                    log.Fatalf("handler error: %v", err)
            }
            if handler == nil {
                    log.Fatalf("empty handler")
            }
            return handler
    }


    Это если нужно передать данные в хандлер на этапе инициализации. Если же при каждом запросе нужно что-то инициализировать - то это можно сделать в самом хандлере. Например:

    package handlers
    
    import (
            "project/context"
            "project/profiler"
    )
    
    type AddItemsRequestData struct {
            Name string `json:"name"`
    }
    
    type AddItems {
            ctx *context.Context
    }
    
    func NewAddItems(ctx *context.Context) (*AddItems, error) {
            return &AddItems{
                    ctx: ctx,
            }, nil
    }
    
    func (h *AddItems) ServeHTTP(res http.ResponseWriter, req *http.Request) {
            ...
            pr := profiler.New() <-- здесь для каждого запроса пользователя создаётся новый экземпляр
            pr.SetName("name")
            ...
    }


    В качестве project/context используется обычный пакет со структурой в которой хранятся любые объекты. Например:
    package context
    
    import (
            "project/profiler"
    )
    
    // Context содержит необходимые библиотеки, такие как хранилища например
    type Context struct {
            Profiler *profiler.Profiler
    }
    
    // New возвращает новый Context
    func New(
            profiler *profiler.Profiler
    ) (
            *Context,
    ) {
            context := &Context{
                    Profiler: profiler,
            }
            return context
    }
    Ответ написан
    1 комментарий
  • Как шарить экземпляр класса между http хендлерами используя контекст?

    nikonor
    @nikonor
    Программист go, perl
    Как минимум надо приводить интерфейс как-то вот так.

    c := profiler.(*Profiler).GetCounter()

    Но тут есть еще несколько тонких моментов:
    1) если нужны копии, то почему в контекс кладется адрес, а не копия? (я не запускал, просто заметил)
    2) надо бы лочить каунтер при изменении
    Ответ написан
    1 комментарий