将对 Redis 实例的引用传递给 Gorilla/Mux 处理程序
Pass a reference to a Redis instance to a Gorilla/Mux Handler
我在玩一些 Gorilla/Mux and Go-Redis 时试图弄脏我的手,但我在这里遇到了一些实施问题。
基本上我的项目结构如下:
其中 redismanager.go 处理 Redis 客户端的初始化:
package redismanager
import (
"fmt"
"github.com/go-redis/redis"
)
func InitRedisClient() redis.Client {
client := redis.NewClient(&redis.Options{
Addr : "localhost:6379",
Password: "",
DB : 0, //default
})
pong, err := client.Ping().Result()
if( err != nil ){
fmt.Println("Cannot Initialize Redis Client ", err)
}
fmt.Println("Redis Client Successfully Initialized . . .", pong)
return *client
}
其中 main.go 调用 redismanager.InitRedisClient
并初始化 mux.Handlers
:
package main
import (
"github.com/gorilla/mux"
"github.com/go-redis/redis"
"net/http"
"fmt"
"log"
"encoding/json"
"io/ioutil"
"../redismanager"
"../api"
)
type RedisInstance struct {
RInstance *redis.Client
}
func main() {
//Initialize Redis Client
client := redismanager.InitRedisClient()
//Get current redis instance to get passed to different Gorilla-Mux Handlers
redisHandler := &RedisInstance{RInstance:&client}
//Initialize Router Handlers
r := mux.NewRouter()
r.HandleFunc("/todo", redisHandler.AddTodoHandler).
Methods("POST")
fmt.Println("Listening on port :8000 . . .")
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}
现在,我可以在同一个文件中轻松定义并让其正常工作 AddTodoHandler
,例如:
func (c *RedisInstance) AddTodoHandler(w http.ResponseWriter, r *http.Request) {
. . . doSomething
}
但是,为了使事情更加模块化,我试图将所有这些 RouteHandlers
移动到 api
包中各自的文件中。为了做到这一点,我需要传递对 redisHandler
的引用,但是在尝试使用 api
包中的处理程序来实现时我遇到了一些困难。
例如,如果在主体中添加:
r.HandleFunc("/todo/{id}", api.GetTodoHandler(&client)).
Methods("GET")
与gettodo.go
package api
import (
"net/http"
"github.com/gorilla/mux"
"fmt"
"encoding/json"
"github.com/go-redis/redis"
)
func GetTodoHandler(c *RedisInstance) func (w http.ResponseWriter, r *http.Request) {
func (w http.ResponseWriter, r *http.Request) {
. . . doSomething
}
}
效果很好。
我对 Go 还是很陌生,即使经过多次研究和阅读,也没有找到任何更干净的解决方案。
我的做法是否正确,还有更好的吗?
r.HandleFunc("/todo/{id}", redisHandler.api.GetTodoHandler).Methods("GET")
您的 redisHandler
,如 main
中所定义,没有 api
字段,因此这自然无法编译。
如果您在 api
包中重新定义了您的 RedisInstance
类型,并且您在特定于方法的文件中为该类型定义了处理程序方法,那么您可以初始化您的 redisHandler
使用 api.RedisInstance
类型,您可以删除 main.RedisInstance
类型定义:
package main
import (
"github.com/gorilla/mux"
"github.com/go-redis/redis"
"net/http"
"fmt"
"log"
"encoding/json"
"io/ioutil"
"../redismanager"
"../api"
)
func main() {
//Initialize Redis Client
client := redismanager.InitRedisClient()
//Get current redis instance to get passed to different Gorilla-Mux Handlers
redisHandler := &api.RedisInstance{RInstance:&client}
//Initialize Router Handlers
r := mux.NewRouter()
r.HandleFunc("/todo", redisHandler.AddTodoHandler).Methods("POST")
r.HandleFunc("/todo/{id}", redisHandler.GetTodoHandler).Methods("GET")
fmt.Println("Listening on port :8000 . . .")
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}
编写一个函数,将带有 Redis 实例参数的函数转换为 HTTP 处理程序:
func redisHandler(c *RedisInstance,
f func(c *RedisInstance, w http.ResponseWriter, r *http.Request)) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { f(c, w, r) })
}
像这样编写 API 处理程序:
func AddTodoHandler(c *RedisInstance, w http.ResponseWriter, r *http.Request) {
...
}
像这样添加到 mux 中:
r.Handler("/todo", redisHandler(client, api.AddTodoHandler)).Methods("POST")
其中 client
是 Redis 实例。
我建议使用一个 App 结构来初始化数据库和路由。并且所有的 Redis 方法都会在里面被调用。
例如type App struct{Routes *mux.Router, DB *DB_TYPE}
并且会有 App.initializeRoutes
方法。
type App struct {
Router *mux.Router
DB *redis.NewClient
}
func (a *App) Run(addr string) {
log.Fatal(http.ListenAndServe(":8000", a.Router))
}
func (a *App) Initialize(addr, password string, db int) error {
// Connect postgres
db, err := redis.NewClient(&redis.Options{
Addr: addr,
Password: password,
DB: db,
})
if err != nil {
return err
}
// Ping to connection
err = db.Ping()
if err != nil {
return err
}
// Set db in Model
a.DB = db
a.Router = mux.NewRouter()
a.initializeRoutes()
return nil
}
func (a *App) initializeRoutes() {
a.Router.HandleFunc("/todo", a.AddTodoHandler).Methods("POST")
a.Router.HandleFunc("/todo/{id}", a.GetTodoHandler).Methods("GET")
}
// AddTodoHandler has access to DB, in your case Redis
// you can replace the steps for Redis.
func (a *App) AddTodoHandler() {
//has access to DB
a.DB
}
希望你明白了,你甚至可以将模型工作提取到一个单独的结构中,然后将其传递到 func's
我在玩一些 Gorilla/Mux and Go-Redis 时试图弄脏我的手,但我在这里遇到了一些实施问题。
基本上我的项目结构如下:
其中 redismanager.go 处理 Redis 客户端的初始化:
package redismanager
import (
"fmt"
"github.com/go-redis/redis"
)
func InitRedisClient() redis.Client {
client := redis.NewClient(&redis.Options{
Addr : "localhost:6379",
Password: "",
DB : 0, //default
})
pong, err := client.Ping().Result()
if( err != nil ){
fmt.Println("Cannot Initialize Redis Client ", err)
}
fmt.Println("Redis Client Successfully Initialized . . .", pong)
return *client
}
其中 main.go 调用 redismanager.InitRedisClient
并初始化 mux.Handlers
:
package main
import (
"github.com/gorilla/mux"
"github.com/go-redis/redis"
"net/http"
"fmt"
"log"
"encoding/json"
"io/ioutil"
"../redismanager"
"../api"
)
type RedisInstance struct {
RInstance *redis.Client
}
func main() {
//Initialize Redis Client
client := redismanager.InitRedisClient()
//Get current redis instance to get passed to different Gorilla-Mux Handlers
redisHandler := &RedisInstance{RInstance:&client}
//Initialize Router Handlers
r := mux.NewRouter()
r.HandleFunc("/todo", redisHandler.AddTodoHandler).
Methods("POST")
fmt.Println("Listening on port :8000 . . .")
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}
现在,我可以在同一个文件中轻松定义并让其正常工作 AddTodoHandler
,例如:
func (c *RedisInstance) AddTodoHandler(w http.ResponseWriter, r *http.Request) {
. . . doSomething
}
但是,为了使事情更加模块化,我试图将所有这些 RouteHandlers
移动到 api
包中各自的文件中。为了做到这一点,我需要传递对 redisHandler
的引用,但是在尝试使用 api
包中的处理程序来实现时我遇到了一些困难。
例如,如果在主体中添加:
r.HandleFunc("/todo/{id}", api.GetTodoHandler(&client)).
Methods("GET")
与gettodo.go
package api
import (
"net/http"
"github.com/gorilla/mux"
"fmt"
"encoding/json"
"github.com/go-redis/redis"
)
func GetTodoHandler(c *RedisInstance) func (w http.ResponseWriter, r *http.Request) {
func (w http.ResponseWriter, r *http.Request) {
. . . doSomething
}
}
效果很好。
我对 Go 还是很陌生,即使经过多次研究和阅读,也没有找到任何更干净的解决方案。
我的做法是否正确,还有更好的吗?
r.HandleFunc("/todo/{id}", redisHandler.api.GetTodoHandler).Methods("GET")
您的 redisHandler
,如 main
中所定义,没有 api
字段,因此这自然无法编译。
如果您在 api
包中重新定义了您的 RedisInstance
类型,并且您在特定于方法的文件中为该类型定义了处理程序方法,那么您可以初始化您的 redisHandler
使用 api.RedisInstance
类型,您可以删除 main.RedisInstance
类型定义:
package main
import (
"github.com/gorilla/mux"
"github.com/go-redis/redis"
"net/http"
"fmt"
"log"
"encoding/json"
"io/ioutil"
"../redismanager"
"../api"
)
func main() {
//Initialize Redis Client
client := redismanager.InitRedisClient()
//Get current redis instance to get passed to different Gorilla-Mux Handlers
redisHandler := &api.RedisInstance{RInstance:&client}
//Initialize Router Handlers
r := mux.NewRouter()
r.HandleFunc("/todo", redisHandler.AddTodoHandler).Methods("POST")
r.HandleFunc("/todo/{id}", redisHandler.GetTodoHandler).Methods("GET")
fmt.Println("Listening on port :8000 . . .")
// Bind to a port and pass our router in
log.Fatal(http.ListenAndServe(":8000", r))
}
编写一个函数,将带有 Redis 实例参数的函数转换为 HTTP 处理程序:
func redisHandler(c *RedisInstance,
f func(c *RedisInstance, w http.ResponseWriter, r *http.Request)) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { f(c, w, r) })
}
像这样编写 API 处理程序:
func AddTodoHandler(c *RedisInstance, w http.ResponseWriter, r *http.Request) {
...
}
像这样添加到 mux 中:
r.Handler("/todo", redisHandler(client, api.AddTodoHandler)).Methods("POST")
其中 client
是 Redis 实例。
我建议使用一个 App 结构来初始化数据库和路由。并且所有的 Redis 方法都会在里面被调用。
例如type App struct{Routes *mux.Router, DB *DB_TYPE}
并且会有 App.initializeRoutes
方法。
type App struct {
Router *mux.Router
DB *redis.NewClient
}
func (a *App) Run(addr string) {
log.Fatal(http.ListenAndServe(":8000", a.Router))
}
func (a *App) Initialize(addr, password string, db int) error {
// Connect postgres
db, err := redis.NewClient(&redis.Options{
Addr: addr,
Password: password,
DB: db,
})
if err != nil {
return err
}
// Ping to connection
err = db.Ping()
if err != nil {
return err
}
// Set db in Model
a.DB = db
a.Router = mux.NewRouter()
a.initializeRoutes()
return nil
}
func (a *App) initializeRoutes() {
a.Router.HandleFunc("/todo", a.AddTodoHandler).Methods("POST")
a.Router.HandleFunc("/todo/{id}", a.GetTodoHandler).Methods("GET")
}
// AddTodoHandler has access to DB, in your case Redis
// you can replace the steps for Redis.
func (a *App) AddTodoHandler() {
//has access to DB
a.DB
}
希望你明白了,你甚至可以将模型工作提取到一个单独的结构中,然后将其传递到 func's