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

在CSDN学Golang场景化解决方案(基于gin框架的web开发脚手架)

一,中间件统一实现Oauth2身份验证

在Golang基于Gin框架开发Web应用程序时,可以使用gin-oauth2来实现Oauth2身份验证。下面是简单的步骤:

  1. 安装gin-oauth2包:go get github.com/appleboy/gin-oauth2
  2. 导入依赖:import "github.com/appleboy/gin-oauth2"
  3. 创建oauth2中间件:
func oauthMiddleware() gin.HandlerFunc {return func(c *gin.Context) {config := oauth2.Config{ClientID:     "CLIENT_ID",ClientSecret: "CLIENT_SECRET",Endpoint:     google.Endpoint,}token, err := oauth2.New(config).ValidateToken(c.Request)if err != nil {c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid Token"})c.Abort()return}// 将token存储到context中以供后续处理使用c.Set("token", token)}
}
  1. 在路由中使用oauth2中间件:
router.GET("/private", oauthMiddleware(), func(c *gin.Context) {// 从context中获取token并进行相关处理token, exists := c.Get("token")if !exists {// handle error}...
})

这样,在访问路由"/private"之前,会先执行oauthMiddleware()函数进行身份验证,只有通过验证才能访问该路由。

需要注意的是,以上示例使用了Google作为OAuth提供商,如果你要使用其他提供商,请根据其文档更新配置信息即可。

二,路由分组api版本控制

在Golang基于Gin框架开发Web应用程序时,可以使用路由分组和api版本控制来管理不同版本的API。下面是简单的步骤:

  1. 导入依赖:import "github.com/gin-gonic/gin"
  2. 创建路由组:
v1 := router.Group("/v1")
{v1.GET("/users", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "API V1"})})
}
v2 := router.Group("/v2")
{v2.GET("/users", func(c *gin.Context) {c.JSON(http.StatusOK, gin.H{"message": "API V2"})})
}
  1. 在需要进行版本控制的地方,根据请求头部信息决定调用哪个版本的API:
router.GET("/users", func(c *gin.Context) {version := c.GetHeader("Accept-Version")switch version {case "application/vnd.example.v1+json":// 调用V1版本的APIbreakcase "application/vnd.example.v2+json":// 调用V2版本的APIbreakdefault:// 版本不支持或未指定c.JSON(http.StatusUnsupportedMediaType, gin.H{"error": "Unsupported Media Type"})return}
})

这样,在访问"/v1/users"或"/v2/users"时,会分别调用对应版本的API;而在访问"/users"时,则会根据请求头部信息来决定调用哪个版本的API。

需要注意的是,以上示例中使用了自定义的请求头部信息来指定API版本,如果你想使用其他方式进行版本控制,也可以根据实际情况进行修改。

三,jwt实现客户端令牌

在Golang基于Gin框架开发Web应用程序时,可以使用JWT(JSON Web Token)来实现客户端令牌。下面是简单的步骤:

  1. 导入依赖:import "github.com/dgrijalva/jwt-go"
  2. 定义JWT生成函数:
func generateToken(userId int64) (string, error) {token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{"userId": userId,"exp": time.Now().Add(time.Hour * 24).Unix(),})return token.SignedString([]byte("your-secret-key"))
}
  1. 定义JWT验证中间件:
func authMiddleware() gin.HandlerFunc {return func(c *gin.Context) {tokenString := c.GetHeader("Authorization")if tokenString == "" {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})return}claims := jwt.MapClaims{}token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (interface{}, error) {return []byte("your-secret-key"), nil})if err != nil || !token.Valid {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid Token"})return}userIdFloat64, ok := claims["userId"].(float64)if !ok {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Invalid User ID"})return}userId := int64(userIdFloat64)// 将用户ID存储到上下文中,以便后续使用c.Set("userId", userId)// 继续处理请求c.Next()}
}
  1. 在需要进行认证的路由上应用中间件:
router.GET("/users/:id", authMiddleware(), func(c *gin.Context) {userId := c.GetInt64("userId")id, err := strconv.ParseInt(c.Param("id"), 10, 64)if err != nil || userId != id {c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "Unauthorized"})return}// 处理请求...
})

这样,在访问"/users/:id"时,会检查请求头部信息中的Authorization字段是否为有效的JWT令牌,并将其中包含的用户ID存储到上下文中。在后续处理中,可以通过从上下文中获取用户ID来实现权限控制。

需要注意的是,以上示例中使用了简单的对称加密方式来生成和验证JWT令牌,如果你想使用其他加密算法或更复杂的认证方案,也可以根据实际情况进行修改。

四,logurs日志组件封装

在Golang基于Gin框架开发Web应用程序时,可以使用logrus来实现日志记录。下面是一个简单的封装示例:

  1. 导入依赖:import log "github.com/sirupsen/logrus"
  2. 定义初始化函数:
func initLogger() {// 设置日志格式为JSON格式log.SetFormatter(&log.JSONFormatter{})// 设置日志级别为debug以上log.SetLevel(log.DebugLevel)// 输出到文件file, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)if err == nil {log.SetOutput(file)} else {log.Info("Failed to log to file, using default stderr")}// 输出到控制台log.SetOutput(os.Stdout)
}
  1. 在main函数中调用初始化函数:
func main() {initLogger()// ...router.Run(":8080")
}
  1. 封装logger对象:
type Logger struct {
}func (l *Logger) Info(args ...interface{}) {log.Info(args...)
}func (l *Logger) Warn(args ...interface{}) {log.Warn(args...)
}func (l *Logger) Error(args ...interface{}) {log.Error(args...)
}func (l *Logger) Fatal(args ...interface{}) {log.Fatal(args...)
}func (l *Logger) Panic(args ...interface{}) {log.Panic(args...)
}
  1. 在需要记录日志的地方使用封装后的logger对象:
logger := &Logger{}
logger.Info("message")

这样,在记录日志时,就可以通过封装后的logger对象来实现。

需要注意的是,以上示例中使用了logrus来输出日志到文件和控制台。如果你想使用其他方式(例如输出到ELK等),也可以根据实际情况进行修改。

五,分布式日志链路追踪设计

在Golang基于Gin框架开发Web应用程序时,为了方便进行分布式日志链路追踪,可以使用Jaeger等开源工具。下面是一个简单的设计示例:

  1. 导入依赖:import ( "github.com/gin-gonic/gin" opentracing "github.com/opentracing/opentracing-go" jaegercfg "github.com/uber/jaeger-client-go/config" log "github.com/sirupsen/logrus" )
  2. 定义初始化函数:
func initTracer() {// 配置jaeger客户端cfg, err := jaegercfg.FromEnv()if err != nil {log.WithError(err).Fatal("Could not parse Jaeger env vars")}tracer, closer, err := cfg.NewTracer(jaegercfg.Logger(log.StandardLogger()))if err != nil {log.WithError(err).Fatal("Could not initialize jaeger tracer")}// 设置全局traceropentracing.SetGlobalTracer(tracer)// 注册gin中间件router.Use(func(c *gin.Context) {spanCtx, _ := tracer.Extract(opentracing.HTTPHeaders, opentracing.HTTPHeadersCarrier(c.Request.Header))span := tracer.StartSpan(c.Request.URL.Path, ext.RPCServerOption(spanCtx))defer span.Finish()c.Set("span", span)c.Next()statusCode := c.Writer.Status()if statusCode >= 400 && statusCode < 500 {span.SetTag("error", true)} else {span.SetTag("success", true)}span.SetTag("http.status_code", statusCode)})// defer关闭tracerdefer closer.Close()
}
  1. 在main函数中调用初始化函数:
func main() {initTracer()// ...router.Run(":8080")
}
  1. 在需要进行日志记录的地方,使用上下文中的span对象进行追踪:
func someHandler(c *gin.Context) {span, ok := c.Get("span")if !ok {log.Error("Could not retrieve span from context")return}// 使用span记录日志和追踪span.LogFields(log.Fields{"event": "some_event","value": 42,})// ...
}

这样,在Web应用程序中就可以通过Jaeger等开源工具,实现方便的分布式日志链路追踪了。

Golang云原生学习路线图、教学视频、文档资料、面试题资料(资料包括C/C++、K8s、golang项目实战、gRPC、Docker、DevOps等)免费分享 有需要的可以加qun:793221798领取

六,EFK统一日志采集

在Golang基于Gin框架开发Web应用程序时,可以使用EFK等工具实现统一日志采集。下面是一个简单的设计示例:

  1. 导入依赖:import ( "github.com/gin-gonic/gin" "github.com/elastic/go-elasticsearch/v7" "go.uber.org/zap" )
  2. 初始化Logger:
func initLogger() {config := zap.NewDevelopmentConfig()logger, err := config.Build()if err != nil {log.WithError(err).Fatal("Could not initialize logger")}// 设置全局Loggerzap.ReplaceGlobals(logger)
}
  1. 在main函数中调用初始化函数:
func main() {initLogger()// ...router.Run(":8080")
}
  1. 定义logrus-zap-hook并注册到logrus中:
type LogrusZapHook struct {}func (hook *LogrusZapHook) Levels() []log.Level {return log.AllLevels
}func (hook *LogrusZapHook) Fire(entry *log.Entry) error {switch entry.Level {case log.DebugLevel:zap.L().Debug(entry.Message)case log.InfoLevel:zap.L().Info(entry.Message)case log.WarnLevel:zap.L().Warn(entry.Message)case log.ErrorLevel:zap.L().Error(entry.Message)case log.FatalLevel:zap.L().Fatal(entry.Message)default:panic(fmt.Sprintf("Unhandled log level: %v", entry.Level))}return nil
}func registerLogrusZapHook() {hook := &LogrusZapHook{}log.AddHook(hook)
}
  1. 在需要进行日志记录的地方,使用logrus进行记录:
func someHandler(c *gin.Context) {// 使用logrus记录日志log.WithFields(log.Fields{"event": "some_event","value": 42,}).Info("Hello, world!")// ...
}
  1. 配置EFK中的Logstash或Filebeat等采集工具,将应用程序的日志发送到Elasticsearch。

这样,在Web应用程序中就可以通过EFK等工具,实现统一的日志采集和管理了。

七,viper配置文件读取

在Golang基于Gin框架开发Web应用程序时,可以使用Viper库实现配置文件读取。下面是一个简单的设计示例:

  1. 导入依赖:import ( "github.com/gin-gonic/gin" "github.com/spf13/viper" )
  2. 初始化Viper:
func initViper() {viper.SetConfigName("config") // 配置文件名字viper.AddConfigPath(".") // 配置文件所在路径err := viper.ReadInConfig()if err != nil {log.WithError(err).Fatal("Could not read config file")}
}
  1. 在main函数中调用初始化函数:
func main() {initViper()// ...router.Run(":8080")
}
  1. 定义配置结构体,并使用viper将配置信息绑定到结构体上:
type Config struct {Mode     string `mapstructure:"mode"`Port     int    `mapstructure:"port"`
}func readConfig() (*Config, error) {config := &Config{}err := viper.Unmarshal(config)if err != nil {return nil, err}return config, nil
}
  1. 在需要访问配置信息的地方,通过读取配置结构体来获取配置信息:
func someHandler(c *gin.Context) {config := &Config{}err := viper.Unmarshal(config)if err != nil {log.WithError(err).Error("Failed to read configuration")return}mode := config.Modeport := config.Port// ...
}

这样,在Web应用程序中就可以使用Viper库,方便地读取配置文件中的信息了。

八,etcd应用配置中心

在Golang基于Gin框架开发Web应用程序时,可以使用Etcd作为应用配置中心。下面是一个简单的设计示例:

  1. 导入依赖:import ( "github.com/gin-gonic/gin" "go.etcd.io/etcd/clientv3" )
  2. 初始化Etcd客户端:
func initEtcd() (*clientv3.Client, error) {config := clientv3.Config{Endpoints: []string{"http://localhost:2379"},}client, err := clientv3.New(config)if err != nil {return nil, err}return client, nil
}
  1. 在main函数中调用初始化函数:
func main() {etcdClient, err := initEtcd()if err != nil {log.WithError(err).Fatal("Could not connect to Etcd")}// ...router.Run(":8080")
}
  1. 定义获取配置信息的函数,并通过Etcd客户端从配置中心读取配置信息:
type Config struct {Mode     string `json:"mode"`Port     int    `json:"port"`
}func getConfig(client *clientv3.Client) (*Config, error) {resp, err := client.Get(context.Background(), "/app/config")if err != nil {return nil, err}for _, kv := range resp.Kvs {var config Configerr = json.Unmarshal(kv.Value, &config)if err != nil {return nil, err}return &config, nil}return nil, errors.New("no configuration found in Etcd")
}
  1. 在需要访问配置信息的地方,通过调用获取配置函数来获取配置信息:
func someHandler(c *gin.Context) {config, err := getConfig(etcdClient)if err != nil {log.WithError(err).Error("Failed to read configuration")return}mode := config.Modeport := config.Port// ...
}

这样,在Web应用程序中就可以使用Etcd作为应用配置中心,实现动态配置管理了。

九,redis数据缓存

在Golang基于Gin框架开发Web应用程序时,可以使用Redis作为数据缓存。下面是一个简单的设计示例:

  1. 导入依赖:import ( "github.com/gin-gonic/gin" "github.com/go-redis/redis/v8" )
  2. 初始化Redis客户端:
func initRedis() *redis.Client {return redis.NewClient(&redis.Options{Addr:     "localhost:6379",Password: "", // no password setDB:       0,  // use default DB})
}
  1. 在main函数中调用初始化函数:
func main() {redisClient := initRedis()// ...router.Run(":8080")
}
  1. 定义获取数据的函数,并通过Redis客户端从缓存中读取数据:
func getDataFromCache(redisClient *redis.Client, key string) (string, error) {data, err := redisClient.Get(context.Background(), key).Result()if err != nil && err != redis.Nil {return "", err}return data, nil
}
  1. 定义写入数据的函数,并通过Redis客户端将数据写入缓存:
func setDataToCache(redisClient *redis.Client, key string, value interface{}, expiration time.Duration) error {err := redisClient.Set(context.Background(), key, value, expiration).Err()if err != nil {return err}return nil
}
  1. 在需要访问数据的地方,通过调用获取或写入数据的函数来进行操作:
func someHandler(c *gin.Context) {data, err := getDataFromCache(redisClient, "data_key")if err != nil {log.WithError(err).Error("Failed to read data from cache")return}if data == "" {// 数据不存在缓存中,需要从其他数据源获取,并将其写入缓存// ...err = setDataToCache(redisClient, "data_key", someData, 10*time.Minute)if err != nil {log.WithError(err).Error("Failed to write data to cache")return}data = someData}// 处理数据// ...
}

这样,在Web应用程序中就可以使用Redis作为数据缓存了。在处理请求时,首先尝试从Redis缓存中获取数据,如果数据不存在,则从其他数据源获取,并将其写入Redis缓存。下次再有相同的请求时,直接从Redis缓存中读取即可。

十,mysql数据存储

在Golang基于Gin框架开发Web应用程序时,可以使用MySQL作为数据存储。下面是一个简单的设计示例:

  1. 导入依赖:import ( "github.com/gin-gonic/gin" "gorm.io/gorm" "gorm.io/driver/mysql" )
  2. 初始化数据库:
func initDB() (*gorm.DB, error) {dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True&loc=Local"db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})if err != nil {return nil, err}return db, nil
}
  1. 在main函数中调用初始化函数,并迁移模型:
func main() {db, err := initDB()if err != nil {log.Fatal(err)}// 迁移模型err = db.AutoMigrate(&User{})if err != nil {log.Fatal(err)}// ...router.Run(":8080")
}
  1. 定义模型结构体:
type User struct {gorm.ModelName  string `json:"name"`Email string `json:"email"`
}
  1. 定义处理请求的函数,通过ORM操作数据库:
func createUser(c *gin.Context) {var user Usererr := c.ShouldBindJSON(&user)if err != nil {c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"})return}result := db.Create(&user)if result.Error != nil {c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to create user"})return}c.JSON(http.StatusCreated, user)
}
  1. 在需要访问数据的地方,通过调用ORM方法来进行操作:
func getUser(c *gin.Context) {var user Userid := c.Param("id")result := db.First(&user, id)if result.Error != nil {if errors.Is(result.Error, gorm.ErrRecordNotFound) {c.JSON(http.StatusNotFound, gin.H{"error": "User not found"})} else {c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to get user"})}return}c.JSON(http.StatusOK, user)
}

这样,在Web应用程序中就可以使用MySQL作为数据存储了。在处理请求时,通过ORM操作数据库进行增删改查等操作。

http://www.lryc.cn/news/106877.html

相关文章:

  • 关于Express 5
  • ftrace 原理详细分析
  • UWB定位技术和蓝牙AOA有哪些不同?-高精度室内定位技术对比
  • 【RabbitMQ】golang客户端教程2——工作队列
  • 芯旺微冲刺IPO,车规级MCU竞争白热化下的“隐忧”凸显
  • HTML <s> 标签
  • 微信小程序 - scroll-view组件之上拉加载下拉刷新(解决上拉加载不触发)
  • rust usize与i64怎么比较大小?
  • 电脑更新win10黑屏解决方法
  • STM32入门——外部中断
  • 【计算机网络】NAT及Bridge介绍
  • 封装动态SQL的插件
  • C# Microsoft消息队列服务器的使用 MSMQ
  • Kafka3.0.0版本——生产者如何提高吞吐量
  • js精度丢失的问题
  • C++ 编译预处理
  • 备战秋招 | 笔试强化22
  • LeetCode ACM模式——哈希表篇(二)
  • hadoop 3.1.3集群搭建 ubuntu20
  • 备忘录模式——撤销功能的实现
  • Golang 函数参数的传递方式 值传递,引用传递
  • K8s影响Pod调度和Deployment
  • 透明代理和不透明代理
  • 1424. 对角线遍历 II;2369. 检查数组是否存在有效划分;1129. 颜色交替的最短路径
  • 【漏洞复现】Metabase 远程命令执行漏洞(CVE-2023-38646)
  • Linux 9的repo for OVS build
  • DOCTYPE 是什么作用?
  • KubeSphere 3.4.0 发布:支持 K8s v1.26
  • 自然语言文本分类模型代码
  • Prometheus实现系统监控报警邮件