Несколько обработчиков на один роут

package main

import (
    "database/sql"
    "net/http"
    "text/template"

    _ "github.com/lib/pq"
)

type Names struct {
    IdU     string
    Name    string
    SecName string
}
type Products struct {
    Id      string
    Company string
    Model   string
    Price   string
}

var dbconnect string = "host=192.168.1.103 port=5432 user=postgres dbname=phones sslmode=disable password=mypass"
var templData, _ = template.ParseFiles("./user.html")
//получаем данные из бд и создаем по ним слайс
func GetProds() []Products {
    db, _ := sql.Open("postgres", dbconnect)
    rowsProducts, _ := db.Query("select * from Products")
    db.Close()
    var Pr []Products
    for rowsProducts.Next() {
        p := Products{}
        rowsProducts.Scan(&p.Id, &p.Model, &p.Company, &p.Price)
        Pr = append(Pr, p)
    }
    rowsProducts.Close()
    return Pr
}


//получаем данные из бд и создаем по ним слайс
func GetNames() []Names {
    db, _ := sql.Open("postgres", dbconnect)
    rowsNames, _ := db.Query("select * from Names")
    db.Close()
    var Na []Names
    for rowsNames.Next() {
        n := Names{}
        rowsNames.Scan(&n.IdU, &n.Name, &n.SecName)
        Na = append(Na, n)
    }
    rowsNames.Close()
    return Na
}

//перебираем данные в слайсе который вернула функция GetProds и выводим в html
func RangeProdsHandleFunc(w http.ResponseWriter, r *http.Request) {
    for _, pr := range GetProds() {
        dataprods := Products{
            Id:      pr.Id,
            Model:   pr.Model,
            Company: pr.Company,
            Price:   pr.Price,
        }
        templData.ExecuteTemplate(w, "products", dataprods)
    }
}
//перебираем данные в слайсе который вернула функция GetNames и выводим в html
func RangeNamesHandleFunc(w http.ResponseWriter, r *http.Request) {
    for _, na := range GetNames() {
        datanames := Names{
            IdU:     na.IdU,
            Name:    na.Name,
            SecName: na.SecName,
        }
        templData.ExecuteTemplate(w, "users", datanames)
    }
}

func main() {
    http.HandleFunc("/data", RangeProdsHandleFunc)
    http.HandleFunc("/data", RangeNamesHandleFunc)
    http.ListenAndServe(":8181", nil)
}

Написал код, который должен выводить в html 2 разных слайса. Сперва циклы функций RangeNamesHandleFunc и RangeProdsHandleFunc были записаны в одну функцию(далее handler) и обрабатывали обращение к роуту /data, путем перебирания 2х слайсов в 2х циклах. и все корректно отображалось в html

Но потом я решил, что в случае расширения функционала, придется расширять handler и, чем больше функционала, тем больше handler(функция может вырасти до неприличных размеров). Поэтому я решил найти способ переписать заполнение слайсов и сделать его в разных функциях и, в принципе, все успешно, но, в итоге, получились два разных hendler-а, которые по сути должны обрабатывать обращения к одному роуту, что, конечно, невозможно но я не смог придумать способ реализовать. На роут dataможно повесить только один обработчик.

Отсюда я задаю вам вопрос, как мне сделать, чтоб эти 2 handler обрабатывали обращения к одному роуту. Необязательно сохранять подход описанный в представленном коде, но если это возможно, то хорошо. Вот ошибка которую я получаю при запуске

panic: http: multiple registrations for /data я знаю ее причину, но не знаю как это решить. Я совсем нуб в го, поэтому многих подходов не знаю. Возможно знают более опытные го-разработчики.

Благодарю за внимание.

UPD: Если Использовать только один handler(любой) в функции main, то все отрабатывает корректно.


Ответы (1 шт):

Автор решения: Senior Pomidor

2 обработчика на один адрес нельзя. но вам оно и не нужно. можно создать 1 хэндлер, куски кода вынести в функцию по смыслу. вызывать эти функции в этом хэндлере, например, как dataHandler


// перебираем данные в слайсе который вернула функция GetProds и выводим в html
func RangeProdsHandleFunc(w http.ResponseWriter) {
    for _, pr := range GetProds() {
        dataprods := Products{
            Id:      pr.Id,
            Model:   pr.Model,
            Company: pr.Company,
            Price:   pr.Price,
        }
        err := templData.ExecuteTemplate(w,"product",  dataprods)
        if err != nil {
            panic(err)
        }
    }
}
 
// перебираем данные в слайсе который вернула функция GetNames и выводим в html
func RangeNamesHandleFunc(w http.ResponseWriter) {
    for _, na := range GetNames() {
        datanames := Names{
            IdU:     na.IdU,
            Name:    na.Name,
            SecName: na.SecName,
        }
        err := templData.ExecuteTemplate(w, "users", datanames)
        if err != nil {
            panic(err)
        }
    }
}
 
func dataHandler(w http.ResponseWriter, r *http.Request) {
    RangeNamesHandleFunc(w)
    RangeProdsHandleFunc(w)
 
}
 
func main() {
    http.HandleFunc("/data", dataHandler)
    http.ListenAndServe(":8181", nil)
}
→ Ссылка