概述
- 基于前文:https://active.blog.csdn.net/article/details/139213323
- 我们基于此SDK提供的API封装一个公共方法来用于生产环境
封装 nacos-sdk-go
-
我们封装一个 nacos.go 文件, 这个是通用的工具库
package commonimport ("fmt""github.com/nacos-group/nacos-sdk-go/v2/clients""github.com/nacos-group/nacos-sdk-go/v2/clients/config_client""github.com/nacos-group/nacos-sdk-go/v2/clients/naming_client""github.com/nacos-group/nacos-sdk-go/v2/common/constant""github.com/nacos-group/nacos-sdk-go/v2/model""github.com/nacos-group/nacos-sdk-go/v2/vo" )// 定义常量和一些参数默认值 var (clientParam vo.NacosClientParam // 客户端参数缓存nacosIp = "127.0.0.1"nacosPort = uint64(8848)nacosContextPath = "/nacos"nacosNamespaceId stringnacosTimeout = uint64(5000)nacosNotLoadCacheAtStart = truenacosLogDir = "nacos/log"nacosCacheDir = "nacos/cache"nacosLogLevel = "debug" )// 结构体 type NacosParams struct {NacosIp stringNacosPort uint64NacosContextPath stringNacosNamespaceId stringNacosTimeoutMs uint64NacosNotLoadCacheAtStart boolNacosLogDir stringNacosCacheDir stringNacosLogLevel string }// nacos参数实例 var nacosParams NacosParams = NacosParams{NacosIp: nacosIp,NacosPort: nacosPort,NacosContextPath: nacosContextPath,NacosNamespaceId: nacosNamespaceId,NacosTimeoutMs: nacosTimeout,NacosNotLoadCacheAtStart: nacosNotLoadCacheAtStart,NacosLogDir: nacosLogDir,NacosCacheDir: nacosCacheDir,NacosLogLevel: nacosLogLevel, }// InitConfig 初始化配置,允许通过函数参数修改默认配置 func InitNacosParams(paramsModifier func(*NacosParams)) {if paramsModifier != nil {paramsModifier(&nacosParams)} }// 获取当前参数 func GetNacosCurrentParams() NacosParams {return nacosParams }// 获取 nacos客户端参数 func getNacosClientParam() vo.NacosClientParam {// 缓存配置参数if clientParam.ClientConfig != nil {return clientParam}// create ServerConfigsc := []constant.ServerConfig{*constant.NewServerConfig(nacosParams.NacosIp, nacosParams.NacosPort, constant.WithContextPath(nacosParams.NacosContextPath)),}// create ClientConfigcc := *constant.NewClientConfig(constant.WithNamespaceId(nacosParams.NacosNamespaceId),constant.WithTimeoutMs(nacosParams.NacosTimeoutMs),constant.WithNotLoadCacheAtStart(nacosParams.NacosNotLoadCacheAtStart),constant.WithLogDir(nacosParams.NacosLogDir),constant.WithCacheDir(nacosParams.NacosCacheDir),constant.WithLogLevel(nacosParams.NacosLogLevel),)clientParam = vo.NacosClientParam{ClientConfig: &cc,ServerConfigs: sc,}return clientParam }// 获取 NacosNamingClient func getNacosNamingClient() (naming_client.INamingClient, error) {return clients.NewNamingClient(getNacosClientParam()) }// 获取 NacosConfigClient func getNacosConfigClient() (config_client.IConfigClient, error) {return clients.NewConfigClient(getNacosClientParam()) }// 注册服务功能 func NacosRegisterServiceInstance(param vo.RegisterInstanceParam) (bool, error) {client, err := getNacosNamingClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return false, err}return client.RegisterInstance(param) }// 获取服务 func NacosGetService(param vo.GetServiceParam) (model.Service, error) {client, err := getNacosNamingClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return model.Service{}, err}return client.GetService(param) // service, err }// 获取所有服务 func NacosGetAllService(param vo.GetAllServiceInfoParam) (model.ServiceList, error) {client, err := getNacosNamingClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return model.ServiceList{}, err}return client.GetAllServicesInfo(param) }// 获取远程配置 func NacosGetConfig(dataId string, group string) (string, error) {client, err := getNacosConfigClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return "", err}return client.GetConfig(vo.ConfigParam{DataId: dataId,Group: group,}) }// 搜索配置文件 func NacosSearchConfig(params vo.SearchConfigParam) (*model.ConfigPage, error) {client, err := getNacosConfigClient()if err != nil {fmt.Println("NacosGetConfig Error", err.Error())return nil, err}return client.SearchConfig(params) }// 监听远程配置改动 回调函数类型 type ConfigChangeListener func(namespace, group, dataId, data string)// 监听远程配置改动 func NacosListenConfigWithCallback(dataId, group string, onChange ConfigChangeListener) error {client, err := getNacosConfigClient()if err != nil {fmt.Println("getNacosNamingClient Error", err.Error())return err}err = client.ListenConfig(vo.ConfigParam{DataId: dataId,Group: group,OnChange: func(namespace, group, dataId, data string) {// 当配置变更时,调用传入的回调函数onChange(namespace, group, dataId, data)},})return err }
- 可以看到,上述集成了服务和配置两大类API
- 服务
- 注册服务
- 获取服务
- 获取所有服务
- 配置
- 获取远程配置
- 搜索配置文件
- 监听远程配置改动回调
- 其他未实现封装
- 比如:批量注册服务,注销服务,更新服务
- 比如:选择所有实例,选择实例,选择健康实例,订阅,取消订阅
- 比如:发布配置,删除配置,取消监听配置
- 后续可以根据官方提供的其他api继续添加
-
源码仓库:https://gitee.com/go-micro-services/common/blob/master/nacos.go
应用封装
1 )概述
- 这里,我们应用在一个客户端,比如一个网关中
- 这里使用gin框架+go-micro来实现封装的sdk
2 )目录结构
gitee.com/go-micro-services/nacos-go-micro-gin├── conf # 当前位置文件│ └── conf.go├── routers # 路由│ └── router.go├── controllers # 控制器│ └── api.go├── nacos # nacos目录,后续生成,此文件写入 .gitignore│ ├── cache│ └── log├── main.go├── go.mod└── .gitignore
3 ) 源码
- 仓库地址:https://gitee.com/go-micro-services/nacos-go-micro-gin
3.1 conf/conf.go
package confvar (NacosIp = "127.0.0.1"NacosPort = uint64(8848)NacosTimeoutMs = uint64(5000)NacosContextPath = "/nacos"NacosNamespaceId = "ff2e8758-33c1-4a88-8005-142cbee91be9" // 这个是配置命名空间后生成的NacosLogDir = "nacos/log"NacosCacheDir = "nacos/cache"NacosLogLevel = "debug"NacosServiceName = "nacos-go-micro-gin"NacosGroupName = "dd"NacosNotLoadCacheAtStart = trueNacosMetadata = map[string]string{"idc": "shanghai"}NacosDataId = "test.json" // 这个是自己在nacos后台自己配置的NacosGroup = "tt" // 同上
)
- 这里做了一个简单的通用配置,一般要拆分环境来管理
- 这里做一个简单的示例
3.2 routers/router.go
package routersimport ("gitee.com/go-micro-services/nacos-go-micro-gin/controllers""github.com/gin-gonic/gin"
)func RoutersInit(r *gin.Engine) {rr := r.Group("/"){rr.GET("", controllers.ApiController{}.Index)rr.GET("/service", controllers.ApiController{}.FindService)rr.GET("/getConfig", controllers.ApiController{}.GetConfig)rr.GET("/searchConfig", controllers.ApiController{}.SearchConfig)}
}
- 上面定义了4个路由,分别对应
/
/service
/getConfig
/searchConfig
3.3 controllers/api.go
package controllersimport ("encoding/json""net/http""strings""gitee.com/go-micro-services/common""gitee.com/go-micro-services/nacos-go-micro-gin/conf""github.com/gin-gonic/gin""github.com/nacos-group/nacos-sdk-go/v2/model""github.com/nacos-group/nacos-sdk-go/v2/vo"
)var statusOK = http.StatusOK
var statusBadRequest = http.StatusBadRequesttype ApiController struct{}func (con ApiController) Index(c *gin.Context) {params := vo.GetAllServiceInfoParam{GroupName: conf.NacosGroupName,PageNo: 1,PageSize: 10,}list, err := common.NacosGetAllService(params)// 错误处理if err != nil {// 错误处理c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 正常响应c.JSON(statusOK, list)
}func (con ApiController) FindService(c *gin.Context) {params := vo.GetServiceParam{ServiceName: conf.NacosServiceName,GroupName: conf.NacosGroupName,}list, err := common.NacosGetService(params)// 错误处理if err != nil {// 错误处理c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 正常响应c.JSON(statusOK, list)
}func (con ApiController) GetConfig(c *gin.Context) {content, err := common.NacosGetConfig(conf.NacosDataId, conf.NacosGroup)// 错误处理if err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}var contentJson map[string]interface{}// 解码JSON字符串到maperr = json.Unmarshal([]byte(content), &contentJson)// 错误处理if err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 正常响应c.JSON(statusOK, contentJson)
}func (con ApiController) SearchConfig(c *gin.Context) {// 构造搜索参数params := vo.SearchConfigParam{Search: "blur",DataId: conf.NacosDataId,Group: conf.NacosGroup,PageNo: 1,PageSize: 10,}// 调用接口获得结果var currentPage *model.ConfigPagevar err errorif currentPage, err = common.NacosSearchConfig(params); err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 格式转化var jsonBytes []byteif jsonBytes, err = json.Marshal(currentPage); err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}// 处理特殊字符,这里性能会有影响,可以用一个循环加一个Map来进行替换,而非每次 ReplaceAllstr := strings.ReplaceAll(string(jsonBytes), " ", "")str = strings.ReplaceAll(str, "\\n", "")str = strings.ReplaceAll(str, "\\", "")str = strings.ReplaceAll(str, `"{`, "{")str = strings.ReplaceAll(str, `}"`, "}")// 转换成 jsonvar result map[string]interface{}if err = json.Unmarshal([]byte(str), &result); err != nil {c.JSON(statusBadRequest, gin.H{"err": err.Error(),})return}c.JSON(statusOK, result)
}
- 这是对应上述4个路由的四个控制器的处理
3.4 main.go
package mainimport ("fmt""gitee.com/go-micro-services/common""gitee.com/go-micro-services/nacos-go-micro-gin/conf""gitee.com/go-micro-services/nacos-go-micro-gin/routers""github.com/gin-gonic/gin""github.com/nacos-group/nacos-sdk-go/v2/vo""go-micro.dev/v4/web"
)func init() {// 1. 参数初始化initNacosParams()// 2. 注册regNacos()// 3. 监听listenNacosConfig()
}// 参数初始化
func initNacosParams() {// 初始化配置,并在过程中修改默认值common.InitNacosParams(func(cfg *common.NacosParams) {cfg.NacosIp = conf.NacosIpcfg.NacosPort = conf.NacosPortcfg.NacosNamespaceId = conf.NacosNamespaceIdcfg.NacosLogLevel = conf.NacosLogLevel})// 如果需要,可以随时通过GetCurrentConfig获取配置副本currentConfig := common.GetNacosCurrentParams()fmt.Printf("Retrieved Config - Service Name: %s, Port: %d\n", currentConfig.NacosIp, currentConfig.NacosPort)
}// 注册
func regNacos() {_, err := common.NacosRegisterServiceInstance(vo.RegisterInstanceParam{Ip: conf.NacosIp,Port: conf.NacosPort,ServiceName: conf.NacosServiceName,GroupName: conf.NacosGroupName,// ClusterName: "cluster-a",Weight: 10,Enable: true,Healthy: true,Ephemeral: true,Metadata: conf.NacosMetadata,})if err != nil {fmt.Println("注册发生错误: ", err.Error())}
}// 监听配置改动
func listenNacosConfig() {var namespace, group, dataId stringerr := common.NacosListenConfigWithCallback(conf.NacosDataId, conf.NacosGroup, func(namespace, group, dataId, data string) {namespace = namespacegroup = groupdataId = dataIdfmt.Println("Config changed. Namespace: %s, Group: %s, DataId: %s, Content: %s", namespace, group, dataId, data)})if err != nil {fmt.Println("Failed to listen config for Namespace: %s, DataId: %s, Group: %s. Error: %v", namespace, dataId, group, err)}
}func main() {ginRouter := gin.Default()routers.RoutersInit(ginRouter)srv := web.NewService(web.Metadata(map[string]string{"version": "latest"}),web.Handler(ginRouter), // 服务路由web.Address("0.0.0.0:9999"), // 服务端口)srv.Run()
}
- 这里的main.go主要关注的是上面的 init 函数中的nacos配置
- 这里演示的是客户端,当然服务端也是使用封装后的sdk
演示效果
1 )手动配置的配置文件
2 ) 注册了的服务
3 )API 应用的路由相关返回
其他
- 在 go-micro中,有 nacos 的相关插件,它也是自己的封装
- 但是,在使用的时候,可能不能完全满足所有的nacos的接口实现
- 所以,我个人推荐基于官方提供的api 自行进行封装和扩展,从而不被 go-micro 限制
- 毕竟,框架的使用会有一个通用的问题就是虽然使用方便,但扩展修改可能会受其限制