当前位置: 首页 > wzjs >正文

西安分销商城网站建设关键词歌词任然

西安分销商城网站建设,关键词歌词任然,一般网站模块,网站建设图片怎么做在微服务架构中,Web 层作为系统的入口门面,承担着请求路由、权限校验和服务聚合等核心功能。本文将围绕 Gin 框架与 Consul 注册中心的集成展开,详细讲解 Web 服务如何实现服务注册与发现,帮助你构建可扩展的微服务前端架构。 承接…

在微服务架构中,Web 层作为系统的入口门面,承担着请求路由、权限校验和服务聚合等核心功能。本文将围绕 Gin 框架与 Consul 注册中心的集成展开,详细讲解 Web 服务如何实现服务注册与发现,帮助你构建可扩展的微服务前端架构。
承接微服务注册中心详解

我在前面文章中也写了gRPC服务层集成consul,需要的可以回去看一下。

一、Web 层服务集成 Consul 概述

1.1 Web 层在微服务中的定位

Web 层(如 Gin 服务)通常扮演以下多重角色:

  • API 网关:作为系统统一入口,处理跨域请求、身份认证、流量限流等非业务逻辑,避免底层服务重复实现通用功能
  • 服务聚合器:将多个底层微服务的能力组合成复合 API,减少客户端与后端的交互次数(如同时获取用户信息和订单列表)
  • 请求路由枢纽:根据业务逻辑将请求转发到对应服务,实现前端与后端服务的逻辑解耦
为什么 Web 层需要集成 Consul?

在单体架构中,服务地址通常是硬编码的;但在微服务场景下:

  • 底层服务可能部署多个实例(如用户服务有 3 个副本),需要动态获取可用地址
  • 服务可能因扩缩容、故障转移而变更 IP 端口,手动维护地址列表不现实
  • 负载均衡需要从注册中心获取实时服务列表,实现流量的动态分配

1.2 服务注册与发现的双重需求

1.2.1 服务注册的必要性

即使作为前端服务,Web 层仍需注册到 Consul 的核心原因:

  • 反向调用场景:后台管理系统、数据同步服务可能需要调用 Web 层 API,需通过注册中心获取地址
  • 负载均衡需求:Nginx 等反向代理可从 Consul 动态获取 Web 服务地址,避免手动配置上游服务器
  • 全局服务治理:统一在 Consul 中监控所有服务的健康状态,包括 Web 层的运行情况
1.2.2 服务发现的核心作用

Web 层的服务发现机制解决了三大问题:

  1. 地址动态获取:底层服务(如用户服务)的 IP 端口变更时,Web 层无需重启即可获取新地址
  2. 多实例负载均衡:当同一服务存在多个实例时,自动选择合适的节点调用
  3. 故障自动转移:检测到服务实例不健康时,自动跳过该实例,避免请求失败

二、Consul 配置与服务发现实现

2.2 服务发现核心代码解析

2.2.1 从 Consul 获取服务地址的执行流程

您提供的代码片段展示了从 Consul 获取用户服务地址并建立 gRPC 连接的完整过程。这一过程可以分解为以下关键步骤:

  1. 初始化 Consul 客户端:从配置中读取 Consul 服务器地址并创建客户端
  2. 服务发现查询:通过服务名称过滤获取目标服务实例
  3. 地址解析与连接:提取服务 IP 和端口,建立 gRPC 长连接
  4. 全局客户端管理:将 gRPC 客户端存储为全局变量供后续使用
// service_discovery.go - 服务发现实现
package serviceimport ("fmt""log""github.com/hashicorp/consul/api""your-project/global""zap"
)// InitSrvConn 初始化服务连接
func InitSrvConn() {// 1. 初始化Consul客户端配置cfg := api.DefaultConfig()consulInfo := global.ServerConfig.ConsulInfocfg.Address = fmt.Sprintf("%s:%d", consulInfo.Host, consulInfo.Port)// 2. 创建Consul客户端client, err := api.NewClient(cfg)if err != nil {log.Fatalf("创建Consul客户端失败: %v", err)}// 3. 过滤查询用户服务data, err := client.Agent().ServicesWithFilter(fmt.Sprintf("Service==\"%s\"", global.ServerConfig.UserSrvInfo.Name))if err != nil {log.Fatalf("过滤服务失败: %v", err)}// 4. 解析服务地址userSrvHost := ""userSrvPort := 0fmt.Println("过滤后的服务:")for _, value := range data {userSrvHost = value.AddressuserSrvPort = value.Portbreak}// 5. 验证服务是否找到if userSrvHost == "" {zap.S().Fatal("[InitSrvConn] 连接 用户服务失败")return}// 6. 建立gRPC连接userconn, err := grpc.Dial(fmt.Sprintf("%s:%d", userSrvHost, userSrvPort), grpc.WithInsecure())if err != nil {zap.S().Errorw("[GetUserList] 连接 [用户服务失败]", "message", err.Error())}// 7. 生成gRPC客户端并存储为全局变量userSrvClient := proto.NewUserClient(userconn)global.UserSrvClient = userSrvClientzap.S().Infof("用户服务连接成功: %s:%d", userSrvHost, userSrvPort)
}
2.2.2 在 Gin 中集成服务发现的完整流程

您提供的示例代码展示了在 Gin 路由处理函数中如何使用通过 Consul 发现的服务。下面我将结合您的代码,详细说明服务发现如何与实际业务接口结合:

// main.go - Gin服务启动流程
package mainimport ("context""fmt""github.com/gin-gonic/gin""google.golang.org/grpc""net/http""strconv""time""your-project/global""your-project/proto""your-project/service""your-project/response" // 假设这是模型包"your-project/forms"    // 假设这是表单验证包"your-project/models"   // 假设这是模型包"your-project/utils"    // 假设这是工具包"zap"
)func main() {// 1. 初始化配置initConfig()// 2. 初始化服务连接(从Consul发现服务)service.InitSrvConn()// 3. 初始化Gin引擎r := gin.Default()// 4. 注册中间件setupMiddlewares(r)// 5. 注册路由setupRoutes(r)// 6. 注册Web服务到Consulif err := service.RegisterWebServiceToConsul(); err != nil {panic(fmt.Sprintf("Web服务注册失败: %v", err))}// 7. 启动Gin服务addr := fmt.Sprintf(":%d", global.ServerConfig.Port)zap.S().Infof("服务启动: %s", addr)if err := r.Run(addr); err != nil {panic(fmt.Sprintf("Gin服务启动失败: %v", err))}
}// 用户控制器 - 整合业务接口示例
func setupRoutes(r *gin.Engine) {userGroup := r.Group("/users"){userGroup.GET("/", GetUserList)        // 获取用户列表userGroup.POST("/login", PassWordLogin) // 用户登录}
}// 获取用户列表 - 
func GetUserList(ctx *gin.Context) {// 从JWT中取出用户id(假设JWT验证已通过)claims, exists := ctx.Get("claims")if !exists {ctx.JSON(http.StatusUnauthorized, gin.H{"error": "未授权",})return}currentUser := claims.(*models.CustomClaims)zap.S().Infof("用户信息:%v", currentUser.Id)// 分页参数处理pn := ctx.DefaultQuery("pn", "0")pnInt, _ := strconv.Atoi(pn)pSize := ctx.DefaultQuery("psize", "10")pSizeInt, _ := strconv.Atoi(pSize)// 通过全局变量获取已初始化的gRPC客户端rsp, err := global.UserSrvClient.GetUserList(context.Background(), &proto.PageInfo{Pn:    uint32(pnInt),PSize: uint32(pSizeInt),})if err != nil {zap.S().Errorw("[GetUserList] 查询用户列表失败", "error", err)utils.HandleGrpcErrorToHttp(err, ctx) // 自定义错误处理函数return}// 构建响应数据result := make([]interface{}, 0)for _, value := range rsp.Data {userResponse := response.UserResponse{Id:       value.Id,NickName: value.NickName,Birthday: response.JsonTime(time.Unix(int64(value.BirthDay), 0)),Gender:   value.Gender,Mobile:   value.Mobile,}result = append(result, userResponse)}ctx.JSON(http.StatusOK, result)
}// 用户登录 - 示例接口
func PassWordLogin(c *gin.Context) {zap.S().Infof("用户登录开始")// 表单验证passWordLoginForm := forms.PassWordLoginForm{}if err := c.ShouldBind(&passWordLoginForm); err != nil {utils.HandleValidatorError(c, err) // 自定义验证错误处理return}zap.S().Infof("用户登录表单验证成功")// 验证验证码if !utils.Store.Verify(passWordLoginForm.CaptchaId, passWordLoginForm.Captcha, true) {zap.S().Infof("验证码错误")c.JSON(http.StatusBadRequest, gin.H{"msg": "验证码错误",})return}// 通过全局变量获取gRPC客户端,调用用户服务验证登录rsp, err := global.UserSrvClient.GetUserByMobile(context.Background(), &proto.MobileRequest{Mobile: passWordLoginForm.Mobile,})if err != nil {zap.S().Errorw("[PassWordLogin] 查询用户失败", "error", err)utils.HandleGrpcErrorToHttp(err, c)return}// 验证密码(示例代码,实际应使用加密比较)if passWordLoginForm.PassWord != rsp.PassWord {c.JSON(http.StatusBadRequest, gin.H{"msg": "密码错误",})return}// 生成JWT tokentoken, err := utils.GenerateToken(rsp.Id, rsp.NickName, rsp.Role)if err != nil {c.JSON(http.StatusInternalServerError, gin.H{"msg": "生成token失败",})return}// 返回登录成功响应c.JSON(http.StatusOK, gin.H{"id":         rsp.Id,"nick_name":  rsp.NickName,"token":      token,"expired_at": time.Now().Add(time.Hour * 24).Unix(),})
}

三、Gin 服务集成 Consul 的关键流程解析

3.1 服务发现的时机选择

从代码可以看出,服务发现发生在两个关键阶段:

  1. 应用启动阶段:在main函数中调用service.InitSrvConn(),在服务启动时就完成服务发现和连接建立
  2. 请求处理阶段:在具体的路由处理函数(如GetUserList)中使用已初始化的全局客户端

这种设计的优势在于:

  • 避免首次请求时的延迟(冷启动问题)
  • 通过全局变量复用连接,减少 TCP 握手开销
  • 服务启动时若无法连接下游服务,则直接终止,避免提供不可用服务

3.2 服务发现与业务逻辑的结合

示例代码展示了服务发现如何与实际业务逻辑结合:

  1. 获取用户列表接口

    • 从 JWT 中提取用户身份信息
    • 解析分页参数
    • 调用通过 Consul 发现的用户服务
    • 处理返回结果并构建响应
  2. 用户登录接口

    • 表单验证和验证码校验
    • 调用用户服务验证用户信息
    • 生成 JWT 令牌并返回

3.3 代码组织最佳实践

根据示例代码,建议以下代码组织方式:

  1. 服务发现逻辑:封装在service包中,提供初始化函数(如InitSrvConn
  2. 全局客户端:存储在global包中,供所有需要调用服务的地方使用
  3. 路由处理:按业务模块组织路由和处理函数(如user_routes.go
  4. 工具函数:将通用功能(如错误处理、表单验证)封装在utils包中

四、服务注册中心接口与实现

4.1 服务注册核心接口详解

4.1.1 服务注册的关键参数说明
// consul.go - 服务注册实现中的关键配置项
registration := &api.AgentServiceRegistration{ID:      fmt.Sprintf("%s-%d", config.Name, config.Port), // 服务ID必须唯一,建议使用"服务名-端口"格式Name:    config.Name,                                   // 服务名称,用于服务发现时的查询Address: "0.0.0.0",                                     // 服务绑定地址,0.0.0.0表示监听所有网络接口Port:    config.Port,                                   // 服务端口,需与实际监听端口一致Tags:    []string{"gin", "web-service"},                // 服务标签,可用于过滤(如查询所有Gin框架的服务)Check: &api.AgentServiceCheck{// 健康检查配置核心参数:HTTP:                         fmt.Sprintf("http://127.0.0.1:%d/health", config.Port), // 健康检查URL,建议使用回环地址Interval:                     "10s",       // 检查间隔,过短会增加开销,过长会延迟故障发现Timeout:                      "5s",        // 超时时间,应小于间隔时间DeregisterCriticalServiceAfter: "30s",     // 服务不健康后自动注销的时间,避免长时间保留失效实例},
}
4.1.2 服务注册的最佳实践
  • ID 唯一性:使用服务名 + 端口生成 ID,避免多实例部署时 ID 冲突
  • 健康检查类型:Web 服务建议使用 HTTP 检查(相比 TCP 检查可验证应用层逻辑)
  • 注销延迟DeregisterCriticalServiceAfter建议设为 30-60 秒,给服务重启预留时间
  • 标签规范:通过标签区分服务类型(如 web、srv)、环境(dev、prod)、版本(v1、v2)

4.2 健康检查接口实现原理

4.2.1 健康检查的两种模式
  1. 主动检查:Consul 定期向服务发送请求(如本文实现的 HTTP 检查)
  2. 被动检查:服务主动向 Consul 报告健康状态(适用于网络隔离场景)
4.2.2 健康检查接口的设计要点
// health.go - 健康检查路由实现细节
package routerimport ("github.com/gin-gonic/gin""your-project/global""time"
)// SetupHealthRoutes 配置健康检查路由:
// - 路径固定为/health,符合Consul默认检查规范
// - 返回JSON格式状态,便于机器解析和人工查看
func SetupHealthRoutes(r *gin.Engine) {r.GET("/health", func(c *gin.Context) {// 1. 检查自身服务状态://    - 可添加内存、CPU使用率检查//    - 验证数据库连接、Redis连接等基础资源selfStatus := "UP"if global.ServerConfig.Port == 0 {selfStatus = "DOWN" // 配置未正确加载}// 2. 检查依赖服务状态://    - 此处简化为判断客户端是否存在//    - 生产环境应发送实际请求验证服务可用性depStatus := make(map[string]string)if global.UserSrvClient != nil {// 可选:发送轻量级请求验证服务响应ctx, cancel := context.WithTimeout(context.Background(), 500*time.Millisecond)defer cancel()_, err := global.UserSrvClient.HealthCheck(ctx, &proto.HealthCheckRequest{})if err != nil {depStatus["user-srv"] = "DOWN"} else {depStatus["user-srv"] = "UP"}} else {depStatus["user-srv"] = "DOWN"}// 3. 返回健康状态://    - 200状态码表示整体健康//    - 503状态码表示部分依赖不可用c.JSON(200, gin.H{"status":       selfStatus,"dependencies": depStatus,"timestamp":    time.Now().Unix(),"service":      global.ServerConfig.Name,})})
}

五、测试调试与错误处理

5.1 常见测试场景与调试方法

5.1.1 服务注册验证的三种方式
  1. Consul UI 可视化验证

    • 访问http://consul-host:8500进入 Web 管理界面
    • 在 "Services" 标签页查看user-web服务是否存在
    • 点击服务名称,查看 "Checks" 标签页确认健康检查状态为 "passing"
  2. API 接口验证

    # 查询所有注册服务(返回JSON格式服务列表)
    curl http://consul-host:8500/v1/catalog/services# 查询指定服务的详细信息
    curl http://consul-host:8500/v1/catalog/service/user-web# 验证健康检查接口(需确保Web服务已启动)
    curl http://web-service-host:8021/health
    
  3. 日志动态验证

    • 启动 Web 服务时观察日志,应输出 "Web 服务已注册到 Consul"
    • 查看 Consul 服务器日志,确认收到注册请求
5.1.2 服务发现调试技巧
// 调试服务发现的辅助函数(生产环境建议注释掉)
func debugServiceDiscovery() {serviceName := "user-srv"host, port, err := service.GetServiceAddress(serviceName)if err != nil {log.Fatalf("服务发现失败: 错误详情, %v", err)}// 打印详细的服务元数据,便于调试log.Printf("发现服务 %s 在 %s:%d", serviceName, host, port)// 可选:打印服务的Tags、Meta等信息
}

5.2 错误处理最佳实践

5.2.1 服务发现异常的分级处理
// 带重试和降级的服务发现函数
func GetServiceWithFallback(serviceName string) (string, int, error) {// 1. 定义重试策略:最多重试3次,间隔递增maxRetries := 3for i := 0; i < maxRetries; i++ {host, port, err := service.GetServiceAddress(serviceName)if err == nil {return host, port, nil // 成功获取直接返回}// 打印带重试次数的错误日志,便于问题追踪log.Printf("服务发现失败(尝试 %d/%d): %v", i+1, maxRetries, err)// 指数退避策略:重试间隔逐渐增加,减少服务器压力time.Sleep(time.Duration(i+1) * 2 * time.Second)}// 2. 服务发现失败后的降级处理://    - 从缓存中获取历史地址(需实现缓存机制)//    - 返回预定义的备用地址(如备用服务节点)fallbackHost, fallbackPort := getFallbackServiceAddress(serviceName)if fallbackHost != "" {log.Printf("使用降级地址: %s:%d", fallbackHost, fallbackPort)return fallbackHost, fallbackPort, nil}return "", 0, fmt.Errorf("服务发现重试 %d 次失败且无降级方案", maxRetries)
}
5.2.2 网络异常的全链路处理
// 在gRPC连接中添加完整的错误处理链
userConn, err := grpc.Dial(fmt.Sprintf("%s:%d", host, port),grpc.WithInsecure(),grpc.WithBlock(),grpc.WithTimeout(5*time.Second), // 连接超时控制grpc.WithKeepaliveParams(keepalive.ClientParameters{Time:                10 * time.Second, // 发送心跳间隔Timeout:             3 * time.Second,  // 心跳超时PermitWithoutStream: true,             // 允许在无流时发送心跳}),
)
if err != nil {// 区分临时性错误和永久性错误if opErr, ok := err.(*net.OpError); ok && opErr.Temporary() {log.Printf("临时性连接错误,将尝试重连: %v", err)// 此处可添加重连逻辑} else {log.Printf("永久性连接错误: %v", err)// 记录错误并返回降级响应return nil, err}
}

六、Web 层服务集成 Consul 的优化策略

6.1 连接池与负载均衡的工程实践

6.1.1 连接池实现原理

连接池解决的核心问题:

  • TCP 连接创建开销:每次调用都创建新连接会导致三次握手和四次挥手的性能损耗
  • 文件句柄限制:大量短连接可能耗尽系统文件句柄资源
  • 连接复用效率:复用已有连接可减少网络延迟和资源占用
// 全局连接池实现细节
var (// 连接池配置参数可通过配置文件动态调整userSrvConnPool = &connPool{maxConn: 10,        // 最大连接数,根据服务负载调整conns:   make(chan *grpc.ClientConn, 10), // 缓冲通道实现连接池mu:      sync.Mutex{},                    // 互斥锁保护连接池状态}
)type connPool struct {maxConn intconns   chan *grpc.ClientConnmu      sync.Mutex// 记录连接创建时间,用于超时回收createTimes map[*grpc.ClientConn]time.Time
}// 从连接池获取连接的流程:
// 1. 先从通道中获取空闲连接
// 2. 若通道为空,创建新连接(不超过maxConn限制)
// 3. 检查连接是否可用(避免使用已关闭的连接)
func (p *connPool) Get() (*grpc.ClientConn, error) {select {case conn := <-p.conns:// 检查连接是否有效if err := p.checkConnValid(conn); err != nil {conn.Close()return p.createNewConn()}return conn, nildefault:return p.createNewConn()}
}// 创建新连接时添加服务发现逻辑,确保获取最新地址
func (p *connPool) createNewConn() (*grpc.ClientConn, error) {p.mu.Lock()defer p.mu.Unlock()if len(p.conns) >= p.maxConn {return nil, fmt.Errorf("连接池已满,无法创建新连接")}host, port, err := service.GetServiceAddress("user-srv")if err != nil {return nil, err}conn, err := grpc.Dial(fmt.Sprintf("%s:%d", host, port),grpc.WithInsecure(),grpc.WithBlock(),)if err != nil {return nil, err}// 记录连接创建时间,用于超时回收if p.createTimes == nil {p.createTimes = make(map[*grpc.ClientConn]time.Time)}p.createTimes[conn] = time.Now()return conn, nil
}// 定期清理超时连接的后台goroutine
func (p *connPool) cleanUpExpiredConns() {ticker := time.NewTicker(30 * time.Second)defer ticker.Stop()for range ticker.C {p.mu.Lock()now := time.Now()for conn, createTime := range p.createTimes {if now.Sub(createTime) > 5*time.Minute { // 5分钟未使用的连接conn.Close()delete(p.createTimes, conn)}}p.mu.Unlock()}
}

6.2 生产环境部署建议

6.2.1 Consul 集群高可用配置
  • 节点数量:建议部署 3 或 5 个节点(奇数个),可容忍 1 或 2 个节点故障
  • 数据加密:启用 TLS 加密通信,防止中间人攻击
  • ACL 权限:配置细粒度访问控制,区分服务注册、查询等操作的权限
  • 数据持久化:配置 Raft 日志持久化,确保节点重启后数据不丢失
6.2.2 连接超时与熔断策略
  • 超时设置原则:下游服务的超时时间应小于上游服务的超时时间
  • 熔断触发条件:连续失败次数超过阈值(如 5 次)则触发熔断
  • 熔断恢复策略:设置半开状态,定期尝试少量请求,成功后恢复正常
  • 降级响应设计:熔断期间返回预定义的降级响应,避免前端报错
6.2.3 配置动态更新机制
  1. 监听 Consul KV 变更

    // 监听配置变更的后台goroutine
    func watchConfigChanges() {client, err := getConsulClient()if err != nil {log.Fatalf("创建Consul客户端失败: %v", err)}kv := client.KV()lastIndex := uint64(0)for {// 查询配置键值对,带阻塞查询options := &api.QueryOptions{WaitIndex: lastIndex,WaitTime:  10 * time.Second,}pair, meta, err := kv.Get("config/web-service", options)if err != nil {log.Printf("查询配置失败: %v", err)time.Sleep(1 * time.Second)continue}if pair != nil {// 解析新配置并更新全局配置if err := updateGlobalConfig(pair.Value); err != nil {log.Printf("更新配置失败: %v", err)}}lastIndex = meta.LastIndex}
    }
    
  2. 配置更新注意事项

    • 避免频繁更新导致服务抖动,设置最小更新间隔
    • 关键配置(如数据库连接)更新时需平滑过渡
    • 配置更新后记录变更日志,便于问题追溯

七、完整项目结构参考

通过本文的实践,我们完成了 Gin Web 服务与 Consul 注册中心的深度集成,覆盖了从服务注册、服务发现到健康检查、错误处理的全流程。在实际项目中,Web 层作为微服务的门面,其稳定性直接影响用户体验,合理利用 Consul 的服务治理能力能够有效提升系统的可靠性和可维护性。建议结合业务特点进一步完善负载均衡策略、连接池管理和动态配置更新机制,打造真正健壮的微服务前端架构。当遇到问题时,可通过 Consul UI、日志分析和服务发现调试工具逐步定位,确保每个环节的稳定性。

web-service/
├── config/                  # 配置文件目录,采用环境隔离设计
│   ├── base.yaml            # 基础公共配置,包含各环境通用参数
│   ├── dev.yaml             # 开发环境配置,包含本地服务地址
│   ├── test.yaml            # 测试环境配置,指向测试集群
│   └── prod.yaml            # 生产环境配置,指向正式集群
├── global/                  # 全局状态管理
│   ├── global.go            # 存储全局配置、客户端等对象
│   └── constants.go         # 定义项目常量
├── initialize/              # 初始化逻辑封装
│   ├── config.go            # 配置文件解析与验证
│   ├── consul.go            # Consul客户端初始化与服务注册
│   ├── logger.go            # 日志系统初始化
│   └── grpc.go              # gRPC客户端连接初始化
├── proto/                   # gRPC服务定义
│   ├── user.proto           # 用户服务接口定义(.proto文件)
│   ├── user_grpc.pb.go      # 生成的gRPC客户端代码
│   └── user.pb.go           # 生成的消息结构体代码
├── service/                 # 核心业务逻辑
│   ├── discovery.go         # 服务发现实现,包含负载均衡
│   ├── registration.go      # 服务注册实现,包含健康检查
│   ├── connection_pool.go   # gRPC连接池实现
│   └── fallback.go          # 服务降级逻辑
├── router/                  # 路由配置
│   ├── routes.go            # 主路由注册,包含中间件
│   ├── health.go            # 健康检查路由
│   ├── user_routes.go       # 用户相关API路由
│   └── auth_routes.go       # 认证授权路由
├── handler/                 # 接口处理函数
│   ├── user_handler.go      # 用户信息查询、修改等接口
│   ├── auth_handler.go      # 登录、token管理等接口
│   ├── order_handler.go     # 订单相关接口(示例)
│   └── middleware.go        # 自定义中间件(如JWT认证)
├── model/                   # 数据模型
│   ├── request.go           # 请求参数结构体
│   ├── response.go          # 响应结果结构体
│   └── entity.go            # 业务实体模型
├── utils/                   # 工具函数
│   ├── jwt.go               # JWT生成与验证
│   ├── redis.go             # Redis操作封装
│   └── error.go             # 错误处理工具
└── main.go                  # 程序入口,包含启动流程


对于这篇文章如果大家对微服务不是很熟练的话,主要前四部分就好。可以看到在第五部分我也写到了负载均衡,对于简化配置来说,这是一个很重要的内容,后面的文章我会尽快写到。

还有就是可以看到在第三部分的举例中,我其实是将InitSrvConn 初始化服务连接这部分代码作为全局变量来写的,这就大大简化了代码量,如果不设一个全局变量,你每次都要建立一次连接,这不符合开发原则,所以关于全局变量的实践我后面会单独出一篇文章来写。

制作不易,大概花了6小时来写,如果这篇文章对大家有帮助可以点赞关注,你的支持就是我的动力😊!

http://www.dtcms.com/wzjs/40192.html

相关文章:

  • 宿州做网站全网营销方案
  • 贵阳论坛网站建设百度小说风云榜总榜
  • 个人网站转企业网站免费公司网站建站
  • vr 做的网站临沂seo网站管理
  • 山西晋中网站建设浙江网站seo
  • 搭建网站备案高粱seo博客
  • 独立站建站东莞宁波seo外包服务
  • 国务院 网站建设发展指引seo网站推广培训
  • 建设银行住房租赁品牌百度网盘优化
  • 网站空间的权限深圳白帽优化
  • 徐州企业网站建设公司吉林网站seo
  • 连网站建设百度爱采购推广效果怎么样?
  • 网站如何连接微信支付网络推广引流是做什么工作
  • 苏州专业高端网站建设整站优化 快速排名
  • 移动的网络网站建设湖南靠谱seo优化
  • 学会网站建设方案大数据营销系统
  • 如何查询网站打开速度做网站哪个公司最好
  • 白云电子商务网站建设百度广告投放价格
  • 网站甲假发头套真头发做的假发网店运营推广实训
  • 单位做网站的目的百度搜索指数排行榜
  • 用java做信息发布网站网站关键词在线优化
  • 深圳网络技术有限公司郑州seo实战培训
  • 推广员网站怎么做深圳优化seo
  • 网站360自然排名要怎么做bing搜索国内版
  • 网站的图片大小规定网站免费推广网站
  • 南京网站建设一条龙已备案域名购买平台
  • 做日本的网站好卖的东西最新网站查询工具
  • 郴州做网站 郴网互联搜索广告排名
  • 如何运营一个行业网站win10必做的优化
  • 做网站只解析www的会怎么样宁波seo怎么做推广渠道