GO(C、C++、Python)语言的认识(三)
·
用go开发企业级项目,给出详细的代码实现
下面以一个企业级用户管理微服务为例,展示 Go 语言开发企业级项目的核心代码实现。该服务包含用户 CRUD、认证授权、日志、配置管理、数据库交互等企业级项目常见模块,采用分层架构(API 层、服务层、数据层)设计。
项目结构(企业级标准分层)
user-service/
├── cmd/ # 程序入口
│ └── server/
│ └── main.go # 主函数
├── internal/ # 内部代码(不对外暴露)
│ ├── api/ # API层(处理HTTP请求)
│ │ ├── handler.go # 处理器
│ │ └── middleware.go # 中间件(认证、日志等)
│ ├── config/ # 配置管理
│ │ └── config.go
│ ├── domain/ # 领域模型
│ │ └── user.go
│ ├── repository/ # 数据访问层
│ │ └── user_repo.go
│ └── service/ # 业务逻辑层
│ └── user_service.go
├── pkg/ # 公共包(可复用)
│ ├── logger/ # 日志工具
│ ├── db/ # 数据库连接
│ └── auth/ # 认证工具
├── configs/ # 配置文件
│ └── config.yaml
└── go.mod
核心代码实现
1. 领域模型(internal/domain/user.go)
定义核心业务实体,与数据库表结构对应。
package domain
import "time"
// User 用户领域模型
type User struct {
ID uint64 `json:"id"` // 用户ID
Username string `json:"username"` // 用户名(唯一)
Password string `json:"-"` // 密码(返回时忽略)
Email string `json:"email"` // 邮箱
Status int `json:"status"` // 状态(1-正常,0-禁用)
CreatedAt time.Time `json:"created_at"` // 创建时间
UpdatedAt time.Time `json:"updated_at"` // 更新时间
}
// UserRepository 数据访问接口(依赖倒置,解耦服务层与数据库)
type UserRepository interface {
Create(user *User) error
GetByID(id uint64) (*User, error)
GetByUsername(username string) (*User, error)
Update(user *User) error
Delete(id uint64) error
}
2. 配置管理(internal/config/config.go)
企业级项目需支持多环境配置(开发 / 测试 / 生产),这里用viper解析 yaml 配置。
package config
import (
"fmt"
"github.com/spf13/viper"
)
// Config 应用配置
type Config struct {
Server ServerConfig `mapstructure:"server"`
Database DatabaseConfig `mapstructure:"database"`
JWT JWTConfig `mapstructure:"jwt"`
}
// ServerConfig 服务配置
type ServerConfig struct {
Port int `mapstructure:"port"`
Env string `mapstructure:"env"` // 环境:dev/test/prod
}
// DatabaseConfig 数据库配置
type DatabaseConfig struct {
DSN string `mapstructure:"dsn"` // 连接串
MaxOpen int `mapstructure:"max_open"` // 最大连接数
MaxIdle int `mapstructure:"max_idle"` // 最大空闲连接
Timeout int `mapstructure:"timeout"` // 超时时间(秒)
}
// JWTConfig 认证配置
type JWTConfig struct {
Secret string `mapstructure:"secret"` // 密钥
Expire int `mapstructure:"expire"` // 过期时间(小时)
}
// Load 加载配置文件
func Load(path string) (*Config, error) {
viper.SetConfigFile(path)
viper.SetConfigType("yaml")
if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("读取配置失败: %v", err)
}
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("解析配置失败: %v", err)
}
return &cfg, nil
}
3. 数据库连接(pkg/db/mysql.go)
企业级项目需管理数据库连接池,避免频繁创建连接。
package db
import (
"database/sql"
"fmt"
"time"
_ "github.com/go-sql-driver/mysql" // MySQL驱动
"user-service/internal/config"
)
// InitMySQL 初始化MySQL连接池
func InitMySQL(cfg config.DatabaseConfig) (*sql.DB, error) {
db, err := sql.Open("mysql", cfg.DSN)
if err != nil {
return nil, fmt.Errorf("连接数据库失败: %v", err)
}
// 配置连接池
db.SetMaxOpenConns(cfg.MaxOpen)
db.SetMaxIdleConns(cfg.MaxIdle)
db.SetConnMaxLifetime(time.Duration(cfg.Timeout) * time.Second)
// 测试连接
if err := db.Ping(); err != nil {
return nil, fmt.Errorf("测试连接失败: %v", err)
}
return db, nil
}
4. 数据访问层(internal/repository/user_repo.go)
实现数据库交互,依赖sql.DB,遵循领域模型定义的接口。
package repository
import (
"database/sql"
"fmt"
"user-service/internal/domain"
)
// UserRepository 数据库实现
type UserRepository struct {
db *sql.DB // 注入数据库连接
}
// NewUserRepository 创建实例
func NewUserRepository(db *sql.DB) *UserRepository {
return &UserRepository{db: db}
}
// Create 创建用户
func (r *UserRepository) Create(user *domain.User) error {
sqlStr := `INSERT INTO users (username, password, email, status, created_at, updated_at)
VALUES (?, ?, ?, ?, ?, ?)`
result, err := r.db.Exec(sqlStr,
user.Username, user.Password, user.Email, user.Status,
user.CreatedAt, user.UpdatedAt,
)
if err != nil {
return fmt.Errorf("插入用户失败: %v", err)
}
// 获取自增ID
id, err := result.LastInsertId()
if err != nil {
return err
}
user.ID = uint64(id)
return nil
}
// GetByID 按ID查询
func (r *UserRepository) GetByID(id uint64) (*domain.User, error) {
sqlStr := `SELECT id, username, password, email, status, created_at, updated_at
FROM users WHERE id = ?`
row := r.db.QueryRow(sqlStr, id)
var user domain.User
err := row.Scan(
&user.ID, &user.Username, &user.Password, &user.Email,
&user.Status, &user.CreatedAt, &user.UpdatedAt,
)
if err == sql.ErrNoRows {
return nil, nil // 无数据返回nil
}
if err != nil {
return nil, fmt.Errorf("查询用户失败: %v", err)
}
return &user, nil
}
// 其他方法(GetByUsername/Update/Delete)实现类似...
5. 业务逻辑层(internal/service/user_service.go)
处理核心业务逻辑(如密码加密、数据校验),依赖领域接口(解耦数据库)。
package service
import (
"errors"
"time"
"golang.org/x/crypto/bcrypt" // 密码加密
"user-service/internal/domain"
"user-service/pkg/auth"
)
// UserService 用户服务
type UserService struct {
repo domain.UserRepository // 依赖接口,而非具体实现
jwtCfg auth.JWTConfig // JWT配置
}
// NewUserService 创建实例
func NewUserService(repo domain.UserRepository, jwtCfg auth.JWTConfig) *UserService {
return &UserService{repo: repo, jwtCfg: jwtCfg}
}
// Register 用户注册
func (s *UserService) Register(username, password, email string) (*domain.User, error) {
// 1. 校验用户名是否已存在
exist, err := s.repo.GetByUsername(username)
if err != nil {
return nil, err
}
if exist != nil {
return nil, errors.New("用户名已存在")
}
// 2. 密码加密(企业级项目必须加密存储)
hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, errors.New("密码加密失败")
}
// 3. 创建用户
now := time.Now()
user := &domain.User{
Username: username,
Password: string(hashPwd),
Email: email,
Status: 1, // 默认为正常状态
CreatedAt: now,
UpdatedAt: now,
}
if err := s.repo.Create(user); err != nil {
return nil, err
}
return user, nil
}
// Login 用户登录(返回JWT令牌)
func (s *UserService) Login(username, password string) (string, error) {
// 1. 查询用户
user, err := s.repo.GetByUsername(username)
if err != nil {
return "", err
}
if user == nil {
return "", errors.New("用户名或密码错误")
}
// 2. 校验密码
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return "", errors.New("用户名或密码错误")
}
// 3. 生成JWT令牌
token, err := auth.GenerateToken(user.ID, s.jwtCfg.Secret, s.jwtCfg.Expire)
if err != nil {
return "", errors.New("生成令牌失败")
}
return token, nil
}
// 其他方法(GetUser/UpdateUser/DeleteUser)实现类似...
6. API 层(HTTP 处理器与中间件)
处理器(internal/api/handler.go)
处理 HTTP 请求,调用服务层,返回 JSON 响应。
package api
import (
"encoding/json"
"net/http"
"strconv"
"user-service/internal/domain"
"user-service/internal/service"
)
// UserHandler API处理器
type UserHandler struct {
userService *service.UserService
}
// NewUserHandler 创建实例
func NewUserHandler(userService *service.UserService) *UserHandler {
return &UserHandler{userService: userService}
}
// RegisterHandler 注册接口
func (h *UserHandler) RegisterHandler(w http.ResponseWriter, r *http.Request) {
// 1. 解析请求体
var req struct {
Username string `json:"username"`
Password string `json:"password"`
Email string `json:"email"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, "请求格式错误", http.StatusBadRequest)
return
}
// 2. 调用服务层
user, err := h.userService.Register(req.Username, req.Password, req.Email)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
// 3. 返回响应
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"code": 0,
"msg": "注册成功",
"data": user,
})
}
// LoginHandler 登录接口
func (h *UserHandler) LoginHandler(w http.ResponseWriter, r *http.Request) {
// 类似注册逻辑:解析请求 -> 调用服务层 -> 返回令牌
// ...
}
// GetUserHandler 查询用户接口(需要认证)
func (h *UserHandler) GetUserHandler(w http.ResponseWriter, r *http.Request) {
// 从URL获取用户ID
idStr := r.PathValue("id") // Go 1.22+支持PathValue
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
http.Error(w, "无效的用户ID", http.StatusBadRequest)
return
}
// 调用服务层查询
user, err := h.userService.GetUser(id)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
if user == nil {
http.Error(w, "用户不存在", http.StatusNotFound)
return
}
// 返回用户信息
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(map[string]interface{}{
"code": 0,
"data": user,
})
}
中间件(认证 + 日志,internal/api/middleware.go)
package api
import (
"log"
"net/http"
"time"
"user-service/pkg/auth"
)
// AuthMiddleware 认证中间件(验证JWT令牌)
func AuthMiddleware(secret string) func(http.Handler) http.Handler {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 从Header获取令牌
tokenStr := r.Header.Get("Authorization")
if tokenStr == "" {
http.Error(w, "未提供令牌", http.StatusUnauthorized)
return
}
// 验证令牌
_, err := auth.ValidateToken(tokenStr, secret)
if err != nil {
http.Error(w, "无效的令牌", http.StatusUnauthorized)
return
}
// 验证通过,继续处理请求
next.ServeHTTP(w, r)
})
}
}
// LogMiddleware 日志中间件(记录请求信息)
func LogMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
// 记录请求方法、路径、耗时
defer func() {
log.Printf(
"method: %s, path: %s, duration: %v",
r.Method, r.URL.Path, time.Since(start),
)
}()
next.ServeHTTP(w, r)
})
}
7. 主程序入口(cmd/server/main.go)
组装所有组件,启动服务。
package main
import (
"log"
"net/http"
"user-service/internal/api"
"user-service/internal/config"
"user-service/internal/repository"
"user-service/internal/service"
"user-service/pkg/db"
)
func main() {
// 1. 加载配置
cfg, err := config.Load("configs/config.yaml")
if err != nil {
log.Fatalf("加载配置失败: %v", err)
}
// 2. 初始化数据库连接
mysqlDB, err := db.InitMySQL(cfg.Database)
if err != nil {
log.Fatalf("初始化数据库失败: %v", err)
}
defer mysqlDB.Close()
// 3. 初始化依赖(依赖注入,解耦组件)
userRepo := repository.NewUserRepository(mysqlDB)
userService := service.NewUserService(userRepo, cfg.JWT)
userHandler := api.NewUserHandler(userService)
// 4. 注册路由
mux := http.NewServeMux()
// 公开接口(无需认证)
mux.HandleFunc("POST /register", userHandler.RegisterHandler)
mux.HandleFunc("POST /login", userHandler.LoginHandler)
// 需认证的接口(应用认证中间件)
authMux := api.AuthMiddleware(cfg.JWT.Secret)(mux)
mux.Handle("GET /users/{id}", authMux)
// 5. 应用日志中间件
server := &http.Server{
Addr: ":" + strconv.Itoa(cfg.Server.Port),
Handler: api.LogMiddleware(mux),
}
// 6. 启动服务
log.Printf("服务启动,端口: %d,环境: %s", cfg.Server.Port, cfg.Server.Env)
if err := server.ListenAndServe(); err != nil {
log.Fatalf("服务启动失败: %v", err)
}
}
企业级特性说明
- 分层架构:API 层(处理 HTTP)→ 服务层(业务逻辑)→ 数据层(数据库交互),职责清晰,便于维护。
- 依赖注入:通过接口解耦各层
go集成微服务框架生态重新实现
下面基于Go 微服务生态主流框架(如 Gin 作为 HTTP 框架、GORM 作为 ORM、Consul 服务注册发现、Jaeger 链路追踪、zap 日志),重新实现企业级用户管理微服务,使其更贴近生产环境的微服务架构。
项目结构(微服务标准架构)
user-service/
├── cmd/ # 程序入口
│ └── server/
│ └── main.go # 主函数(初始化框架、注册服务)
├── internal/ # 内部代码
│ ├── api/ # API层(Gin路由+控制器)
│ │ ├── handler/ # 控制器
│ │ │ └── user.go
│ │ └── router/ # 路由注册
│ │ └── router.go
│ ├── config/ # 配置(viper)
│ │ └── config.go
│ ├── domain/ # 领域模型
│ │ └── user.go
│ ├── repository/ # 数据访问层(GORM)
│ │ └── user.go
│ ├── service/ # 业务层
│ │ └── user.go
│ └── middleware/ # 微服务中间件(认证、追踪、日志)
│ ├── auth.go
│ ├── logger.go
│ └── tracer.go
├── pkg/ # 公共工具
│ ├── registry/ # 服务注册(Consul)
│ ├── trace/ # 链路追踪(Jaeger)
│ └── auth/ # JWT工具
├── configs/ # 配置文件
│ └── config.yaml
└── go.mod
核心依赖(go.mod 关键部分)
require (
github.com/gin-gonic/gin v1.9.1 // HTTP框架
gorm.io/gorm v1.25.3 // ORM框架
gorm.io/driver/mysql v1.5.2 // MySQL驱动
github.com/hashicorp/consul/api v1.20.0 // 服务注册发现
go.opentelemetry.io/otel v1.19.0 // 链路追踪
go.uber.org/zap v1.26.0 // 日志框架
github.com/spf13/viper v1.18.2 // 配置管理
golang.org/x/crypto v0.17.0 // 密码加密
)
核心代码实现
1. 配置管理(internal/config/config.go)
集成微服务必要配置(服务注册、链路追踪、数据库等):
package config
import (
"fmt"
"github.com/spf13/viper"
)
// Config 微服务配置
type Config struct {
Server ServerConfig `mapstructure:"server"`
MySQL MySQLConfig `mapstructure:"mysql"`
JWT JWTConfig `mapstructure:"jwt"`
Consul ConsulConfig `mapstructure:"consul"` // 服务注册
Jaeger JaegerConfig `mapstructure:"jaeger"` // 链路追踪
LogLevel string `mapstructure:"log_level"` // 日志级别
}
// ServerConfig 服务基础配置
type ServerConfig struct {
Name string `mapstructure:"name"` // 服务名(user-service)
Host string `mapstructure:"host"` // 服务IP
Port int `mapstructure:"port"` // 服务端口
}
// MySQLConfig 数据库配置
type MySQLConfig struct {
DSN string `mapstructure:"dsn"`
MaxOpen int `mapstructure:"max_open"`
MaxIdle int `mapstructure:"max_idle"`
}
// JWTConfig 认证配置
type JWTConfig struct {
Secret string `mapstructure:"secret"`
Expire int64 `mapstructure:"expire"` // 过期时间(秒)
}
// ConsulConfig 服务注册配置
type ConsulConfig struct {
Address string `mapstructure:"address"` // Consul地址(如127.0.0.1:8500)
TTL int `mapstructure:"ttl"` // 健康检查间隔(秒)
}
// JaegerConfig 链路追踪配置
type JaegerConfig struct {
Endpoint string `mapstructure:"endpoint"` // Jaeger收集器地址
}
// Load 加载配置
func Load(path string) (*Config, error) {
viper.SetConfigFile(path)
if err := viper.ReadInConfig(); err != nil {
return nil, fmt.Errorf("读取配置失败: %w", err)
}
var cfg Config
if err := viper.Unmarshal(&cfg); err != nil {
return nil, fmt.Errorf("解析配置失败: %w", err)
}
return &cfg, nil
}
2. 领域模型(internal/domain/user.go)
结合 GORM 标签定义数据库映射:
package domain
import (
"time"
"gorm.io/gorm"
)
// User 用户模型(与数据库表映射)
type User struct {
ID uint64 `gorm:"primaryKey;autoIncrement" json:"id"`
Username string `gorm:"size:50;uniqueIndex;not null" json:"username"` // 唯一索引
Password string `gorm:"size:100;not null" json:"-"` // 密码加密存储
Email string `gorm:"size:100;uniqueIndex" json:"email"` // 邮箱唯一
Status int `gorm:"type:int;default:1" json:"status"` // 1-正常,0-禁用
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` // 软删除
}
3. 数据访问层(internal/repository/user.go)
基于 GORM 实现数据库操作:
package repository
import (
"context"
"user-service/internal/domain"
"gorm.io/gorm"
)
// UserRepository 数据访问接口
type UserRepository interface {
Create(ctx context.Context, user *domain.User) error
GetByID(ctx context.Context, id uint64) (*domain.User, error)
GetByUsername(ctx context.Context, username string) (*domain.User, error)
Update(ctx context.Context, user *domain.User) error
}
// userRepository GORM实现
type userRepository struct {
db *gorm.DB
}
func NewUserRepository(db *gorm.DB) UserRepository {
return &userRepository{db: db}
}
// Create 创建用户
func (r *userRepository) Create(ctx context.Context, user *domain.User) error {
return r.db.WithContext(ctx).Create(user).Error
}
// GetByUsername 按用户名查询
func (r *userRepository) GetByUsername(ctx context.Context, username string) (*domain.User, error) {
var user domain.User
err := r.db.WithContext(ctx).Where("username = ?", username).First(&user).Error
if err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil // 无数据返回nil
}
return nil, err
}
return &user, nil
}
// 其他方法(GetByID/Update)实现类似...
4. 业务逻辑层(internal/service/user.go)
结合微服务上下文(链路追踪、日志):
package service
import (
"context"
"errors"
"time"
"user-service/internal/domain"
"user-service/internal/repository"
"user-service/pkg/auth"
"golang.org/x/crypto/bcrypt"
)
// UserService 业务服务接口
type UserService interface {
Register(ctx context.Context, username, password, email string) (*domain.User, error)
Login(ctx context.Context, username, password string) (string, error)
GetUser(ctx context.Context, id uint64) (*domain.User, error)
}
// userService 实现
type userService struct {
repo repository.UserRepository
jwtSec string
jwtExp int64
}
func NewUserService(repo repository.UserRepository, jwtSec string, jwtExp int64) UserService {
return &userService{
repo: repo,
jwtSec: jwtSec,
jwtExp: jwtExp,
}
}
// Register 注册业务逻辑
func (s *userService) Register(ctx context.Context, username, password, email string) (*domain.User, error) {
// 1. 检查用户名是否存在
exist, err := s.repo.GetByUsername(ctx, username)
if err != nil {
return nil, err
}
if exist != nil {
return nil, errors.New("用户名已存在")
}
// 2. 密码加密
hashPwd, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
if err != nil {
return nil, errors.New("密码加密失败")
}
// 3. 创建用户
user := &domain.User{
Username: username,
Password: string(hashPwd),
Email: email,
CreatedAt: time.Now(),
UpdatedAt: time.Now(),
}
if err := s.repo.Create(ctx, user); err != nil {
return nil, err
}
return user, nil
}
// Login 登录业务逻辑(生成JWT)
func (s *userService) Login(ctx context.Context, username, password string) (string, error) {
user, err := s.repo.GetByUsername(ctx, username)
if err != nil {
return "", err
}
if user == nil {
return "", errors.New("用户名或密码错误")
}
// 校验密码
if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
return "", errors.New("用户名或密码错误")
}
// 生成JWT令牌(包含用户ID)
token, err := auth.GenerateToken(user.ID, s.jwtSec, s.jwtExp)
if err != nil {
return "", errors.New("生成令牌失败")
}
return token, nil
}
// 其他方法(GetUser)实现类似...
5. API 层(控制器 + 路由)
控制器(internal/api/handler/user.go)
基于 Gin 处理 HTTP 请求:
package handler
import (
"net/http"
"strconv"
"user-service/internal/service"
"github.com/gin-gonic/gin"
)
// UserHandler 控制器
type UserHandler struct {
userService service.UserService
}
func NewUserHandler(svc service.UserService) *UserHandler {
return &UserHandler{userService: svc}
}
// Register 注册接口
func (h *UserHandler) Register(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required,min=3,max=20"`
Password string `json:"password" binding:"required,min=6"`
Email string `json:"email" binding:"required,email"`
}
// 参数校验
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": err.Error()})
return
}
// 调用业务层
user, err := h.userService.Register(c.Request.Context(), req.Username, req.Password, req.Email)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "注册成功",
"data": user,
})
}
// Login 登录接口
func (h *UserHandler) Login(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": err.Error()})
return
}
token, err := h.userService.Login(c.Request.Context(), req.Username, req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"msg": "登录成功",
"data": gin.H{"token": token},
})
}
// GetUser 查询用户接口(需认证)
func (h *UserHandler) GetUser(c *gin.Context) {
idStr := c.Param("id")
id, err := strconv.ParseUint(idStr, 10, 64)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"code": 400, "msg": "无效的用户ID"})
return
}
user, err := h.userService.GetUser(c.Request.Context(), id)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"code": 500, "msg": err.Error()})
return
}
if user == nil {
c.JSON(http.StatusNotFound, gin.H{"code": 404, "msg": "用户不存在"})
return
}
c.JSON(http.StatusOK, gin.H{
"code": 0,
"data": user,
})
}
路由注册(internal/api/router/router.go)
package router
import (
"user-service/internal/api/handler"
"user-service/internal/middleware"
"github.com/gin-gonic/gin"
)
// InitRouter 初始化路由
func InitRouter(
userHandler *handler.UserHandler,
authMiddleware gin.HandlerFunc,
logMiddleware gin.HandlerFunc,
traceMiddleware gin.HandlerFunc,
) *gin.Engine {
r := gin.Default()
// 全局中间件:日志、链路追踪
r.Use(logMiddleware, traceMiddleware)
// 公开路由(无需认证)
public := r.Group("/api/v1")
{
public.POST("/register", userHandler.Register)
public.POST("/login", userHandler.Login)
}
// 需认证的路由
private := r.Group("/api/v1")
private.Use(authMiddleware) // 应用认证中间件
{
private.GET("/users/:id", userHandler.GetUser)
}
return r
}
6. 微服务中间件
认证中间件(internal/middleware/auth.go)
package middleware
import (
"net/http"
"strings"
"user-service/pkg/auth"
"github.com/gin-gonic/gin"
)
// AuthMiddleware JWT认证中间件
func AuthMiddleware(secret string) gin.HandlerFunc {
return func(c *gin.Context) {
// 从Header获取令牌(格式:Bearer <token>)
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "未提供令牌"})
c.Abort()
return
}
parts := strings.Split(authHeader, " ")
if len(parts) != 2 || parts[0] != "Bearer" {
c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "令牌格式错误"})
c.Abort()
return
}
// 验证令牌
_, err := auth.ValidateToken(parts[1], secret)
if err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"code": 401, "msg": "令牌无效或已过期"})
c.Abort()
return
}
c.Next()
}
}
日志中间件(internal/middleware/logger.go)
基于 zap 实现结构化日志:
package middleware
import (
"time"
"user-service/pkg/logger"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
// LogMiddleware 日志中间件
func LogMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
start := time.Now()
// 处理请求
c.Next()
// 记录日志
logger.Info(
"request completed",
zap.String("method", c.Request.Method),
zap.String("path", c.Request.URL.Path),
zap.Int("status", c.Writer.Status()),
zap.Duration("duration", time.Since(start)),更多推荐


所有评论(0)