淘先锋技术网

首页 1 2 3 4 5 6 7

1. Gin框架概述

Gin 是一个用 Go (Golang) 编写的 web 框架。它具有运行速度快,分组的路由器,良好的异常捕获和错误处理,非常好的支持中间件和 json 等特性。

2. Gin框架安装

在终端输入以下命令下载Gin

go get github.com/gin-gonic/gin

image.png

2.1 编辑 main.go 文件

package main

import "github.com/gin-gonic/gin"

func main() {
    r := gin.Default()
    r.GET("/ping", func(c *gin.Context) {
        c.JSON(200, gin.H{
            "message": "pong",
        })
    })
    // 默认端口 8080
    r.Run()
}

2.2 启动

go run main.go

image.png
可以看到,我们在main方法中声明了 path 为 /ping 的接口,我们使用Postman上请求下
image.png

3. 配置路由

在这里可以做很多事情,比如声明接口是否需要授权、对API进行版本控制等
为了更好的熟悉,我们先定义个需求:

  1. 定义两个接口,分别为获取用户列表、添加用户
  2. 对添加用户接口进行授权验证

3.1 鉴权

3.1.1 准备工作

3.1.1.1 常量类
  • 创建包 constant/server
package server
// 服务相关常量
const (
    // 服务默认端口
	PORT       = ":8080"
    // 默认token
	SECRET     = "4b58856e-c396-4427-656f-4cf053f4bd67"
    // token名称
	TOKEN_NAME = "token"
)

3.1.1.2 工具类
  • 创建包 util/security
package security

import (
	"net/http"
	"MyGo/constant/server"
	"github.com/gin-gonic/gin"
)

// 创建签名
func CreateSign(request *gin.Context) {
	request.Header(server.TOKEN_NAME, server.SECRET)
}

// 验证签名
func VerifySign(request *gin.Context) {
	requestToken := request.GetHeader(server.TOKEN_NAME)
	if requestToken == "" && requestToken != server.SECRET {
		request.JSON(http.StatusInternalServerError, "Token verify fail")
		request.Abort()
		return
	}
}
3.1.1.3 服务类
  • 创建包 service/login
package login

import (
	"net/http"
	"MyGo/util/security"
	"github.com/gin-gonic/gin"
)

// 登录获取Token
func Login(request *gin.Context) {
	security.CreateSign(request)
	request.JSON(http.StatusOK, "请求成功")
}

  • 创建包 service/user
package user

import (
	"net/http"
	userMapper "MyGo/mapper/user"
	"MyGo/model"
	"github.com/gin-gonic/gin"
)

// 查询用户列表
func QueryAll(request *gin.Context) {
	users := userMapper.QueryUsers()
	request.JSON(http.StatusOK, users)
}

// 添加用户
func AddUser(request *gin.Context) {
	var user model.User
	err := request.ShouldBind(&user)
	if err != nil {
		request.JSON(http.StatusInternalServerError, "参数解析失败")
	}
	userMapper.AddUser(&user)
	request.JSON(http.StatusOK, "请求成功")
}

3.1.1.4 配置路由
  • 创建包 router
package router

import (
	"MyGo/service/login"
	userService "MyGo/service/user"
	"MyGo/util/security"
	"github.com/gin-gonic/gin"
)

func InitRouter(r *gin.Engine) {

	// 定义开放API分组
	GroupOpen := r.Group("/login")
	{
		GroupOpen.GET("/login", login.Login)
	}

	// 定义 v1 API分组
	GroupV1 := r.Group("/v1")
	{
		GroupV1.GET("/user/list", userService.QueryAll)
	}

	// 定义 v2 API分组,该分组使用 security 工具类中 VerifySign 函数校验Token
	GroupV2 := r.Group("/v2", security.VerifySign)
	{
		GroupV2.POST("/user/add", userService.AddUser)
	}
}

3.1.1.5 编辑main.go文件
package main

import (
	"MyGo/constant/server"
	"MyGo/router"
	"github.com/gin-gonic/gin"
)

func main() {
	engine := gin.Default()
    // 注册router配置
	router.InitRouter(engine)
	// 默认端口 8080
	engine.Run(server.PORT)
}

3.1.2 测试鉴权

3.1.2.1 测试 v1 分组API

使用Postman请求 /v1/user/list接口
image.png
可以看到,该接口没有token也可以请求成功

3.1.2.1 测试 v2 分组API

使用Postman请求 /v2/user/add 接口
image.png
该接口没有token,请求失败了,提示 “Token verify fail” 错误,证明请求进入了 VerifySign 函数内
在这里插入图片描述

3.1.2.3 获取token再次访问 v2分组API

获取token
image.png
将token写入header再次请求add方法
image.png
请求成功了
image.png
数据也写进去了

3.2 日志

Gin 框架的日志默认只会在控制台输出,咱们利用 Logrus 封装一个中间件,将日志记录到文件中。

3.2.1 安装依赖包

go get github.com/sirupsen/logrus
go get github.com/lestrrat-go/file-rotatelogs
go get github.com/rifflock/lfshook 

3.2.2 添加日志配置

log:
  path: /newCode/go/MyGo/logs
  name: system.log

自动创建目录文件暂时还不了解,所以先手动在该目录下创建 system.log 文件

3.2.3 创建日志工具类

  • 创建包 util/log
package log

import (
    "MyGo/util/config"
    "fmt"
    "github.com/gin-gonic/gin"
    rotatelogs "github.com/lestrrat-go/file-rotatelogs"
    "github.com/rifflock/lfshook"
    "github.com/sirupsen/logrus"
    "os"
    "path"
    "time"
)

func LoggerWrite() gin.HandlerFunc {

    config := config.GetConfig("./config/", "config_dev", config.YAML)
    logFilePath := config.GetString("log.path")
    logFileName := config.GetString("log.name")

    // 日志文件
    fileName := path.Join(logFilePath, logFileName)

    // 写入文件
    src, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_APPEND, 0644)
    if err != nil {
        fmt.Println("err", err)
    }

    // 实例化
    logger := logrus.New()

    // 设置输出
    logger.Out = src

    // 设置日志级别
    logger.SetLevel(logrus.DebugLevel)

    // 设置 rotatelogs
    logWriter, err := rotatelogs.New(
        // 分割后的文件名称
        fileName+".%Y%m%d.log",

        // 生成软链,指向最新日志文件
        rotatelogs.WithLinkName(fileName),

        // 设置最大保存时间(7天)
        rotatelogs.WithMaxAge(7*24*time.Hour),

        // 设置日志切割时间间隔(1天)
        rotatelogs.WithRotationTime(24*time.Hour),
    )

    writeMap := lfshook.WriterMap{
        logrus.InfoLevel:  logWriter,
        logrus.FatalLevel: logWriter,
        logrus.DebugLevel: logWriter,
        logrus.WarnLevel:  logWriter,
        logrus.ErrorLevel: logWriter,
        logrus.PanicLevel: logWriter,
    }

    lfHook := lfshook.NewHook(writeMap, &logrus.JSONFormatter{
        TimestampFormat: "2006-01-02 15:04:05",
    })

    // 新增钩子
    logger.AddHook(lfHook)

    return func(c *gin.Context) {
        // 开始时间
        startTime := time.Now()

        // 处理请求
        c.Next()

        // 结束时间
        endTime := time.Now()

        // 执行时间
        latencyTime := endTime.Sub(startTime)

        // 请求方式
        reqMethod := c.Request.Method

        // 请求路由
        reqUri := c.Request.RequestURI

        // 状态码
        statusCode := c.Writer.Status()

        // 请求IP
        clientIP := c.ClientIP()

        // 日志格式
        logger.WithFields(logrus.Fields{
            "status_code":  statusCode,
            "latency_time": latencyTime,
            "client_ip":    clientIP,
            "req_method":   reqMethod,
            "req_uri":      reqUri,
        }).Info()
    }
}

3.2.4 开启日志

package main

import (
	"MyGo/constant/server"
	"MyGo/router"
	"MyGo/util/log"
	"github.com/gin-gonic/gin"
)

func main() {
	// 默认为 debug 模式,设置为发布模式
	gin.SetMode(gin.ReleaseMode)
	engine := gin.Default()
	// 配置日志
	engine.Use(log.LoggerWrite())
	// 配置路由
	router.InitRouter(engine)
	// 默认端口 8080
	engine.Run(server.PORT)
}

3.2.5 请求接口,校验日志是否开启

image.png
日志信息成功写入文件,但是可以发现是有个failed的

使用的为 win10系统,需要开启开发者模式