gin框架提高篇(四)

参数校验(一)

uuid包:https://github.com/satori/go.uuid

因为作者更改了参数限制,导致会出问题 → 问题解决

go 复制代码
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	uuid "github.com/gofrs/uuid"
	"net/http"
	"unicode/utf8"
)

type UserInfo struct {
	Id   string `validate:"uuid" json:"id"`           // UUID 类型
	Name string `validate:"checkName" json:"name"`    // 自定义校验
	Age  uint8  `validate:"min=0,max=130" json:"age"` // 大于0小于130
}

var validate *validator.Validate

// 校验初始化
func init() {
	validate = validator.New()                              // 初始化校验示例
	validate.RegisterValidation("checkName", checkNameFunc) // 自定义校验方法
}

func checkNameFunc(fl validator.FieldLevel) bool {
	count := utf8.RuneCountInString(fl.Field().String()) // 获取 Name 的字符串表示,并计算 Unicode 字符的数量
	if count >= 2 && count <= 12 {
		return true
	}
	return false
}

func main() {
	uuid.Must(uuid.NewV4()) // 由 uuid包 生成 uuid

	r := gin.Default()
	var user UserInfo
	r.POST("/validate", func(context *gin.Context) {
		err := context.Bind(&user)
		if err != nil {
			context.JSON(http.StatusBadRequest, "请求参数错误")
			return
		}
		err = validate.Struct(user)
		if err != nil {
			for _, e := range err.(validator.ValidationErrors) {
				fmt.Println("错误的字段:", e.Field())
				fmt.Println("错误的值:", e.Value())
				fmt.Println("错误的tag:", e.Tag())
			}
			context.JSON(http.StatusBadRequest, "数据校验失败")
			return
		}
		context.JSON(http.StatusOK, "数据校验成功")
	})
	r.Run(":9090")
}

参数校验(二)

validator包:https://github.com/go-playground/validator

go 复制代码
package main

import (
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/go-playground/validator/v10"
	"net/http"
)

type ValUser struct {
	Name  string `validate:"required" json:"name"`
	Age   uint8  `validate:"gte=0,lte=130" json:"age"`
	Email string `validate:"required,email" json:"email"`
	// 切片数据类型
	Address []ValAddress `validate:"dive" json:"address"`
}

type ValAddress struct {
	Province string `validate:"required" json:"province"`
	City     string `validate:"required" json:"city"`
	Phone    string `validate:"numeric,len=11" json:"phone"`
}

var validate *validator.Validate

func init() {
	validate = validator.New() // 初始化
}

func main() {
	r := gin.Default()
	var user ValUser
	r.POST("/validate", func(context *gin.Context) {
		//testData(context)

		err := context.Bind(&user)
		if err != nil {
			context.JSON(http.StatusBadRequest, "参数错误,绑定失败")
			return
		}
		// 参数校验
		if validateUser(user) {
			context.JSON(http.StatusOK, "数据校验成功")
			return
		}
		context.JSON(http.StatusBadRequest, "校验失败")
		return
	})
	r.Run(":9090")
}

//func testData(context *gin.Context) {
//	address := ValAddress{
//		Province: "浙江省",
//		City:     "杭州市",
//		Phone:    "13575121689",
//	}
//	user := ValUser{
//		Name:    "张三",
//		Age:     15,
//		Email:   "1993036922@qq.com",
//		Address: []ValAddress{address},
//	}
//	context.JSON(http.StatusOK, user)
//}

func validateUser(u ValUser) bool {
	err := validate.Struct(u)
	if err != nil {
		for _, e := range err.(validator.ValidationErrors) {
			fmt.Println("错误的字段:", e.Field())
			fmt.Println("错误的值:", e.Value())
			fmt.Println("错误的tag:", e.Tag())
		}
		return false
	}
	return true
}

swagger

swagger地址:https://github.com/swaggo/gin-swagger

引入步骤

如果出现 swag 不是命令,无法识别,则先执行: go install github.com/swaggo/swag/cmd/swag@latest

ps:文件名必须叫 main

go 复制代码
package main

import (
	_ "2-golang/docs"
	"fmt"
	"github.com/gin-gonic/gin"
	swaggerFiles "github.com/swaggo/files"
	ginSwagger "github.com/swaggo/gin-swagger"
	"net/http"
)

type User struct {
	UserName string `json:"user_name"`
	Password string `json:"password"`
}

type Response struct {
	Code int    `json:"code"`
	Msg  string `json:"msg"`
	Data string `json:"data"`
}

func main() {
	r := gin.Default()
	// 使用 swagger 中间件
	r.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))

	r.GET("/login", login)

	r.POST("/register", register)

	r.Run(":9090")
}

// @Tags 注册接口
// @Summary 注册
// @Description register
// @Accept json
// @Produce json
// @Param username formData string true "用户名"
// @Param password formData string true "密码"
// @Success 200 {string} json "{"code": 200, "data":"{"name":"username","password":"password"}","msg":"OK"}"
// @Router /register [post]
func register(context *gin.Context) {
	var user User
	// get 使用的是 query,post 使用的是 formData,而 Bind 只能绑定 query
	// err := context.Bind(&user)
	err := context.BindQuery(&user)

	if err != nil {
		context.JSON(http.StatusBadRequest, "数据错误")
		return
	}

	res := Response{
		Code: http.StatusOK,
		Msg:  "注册成功",
		Data: "OK",
	}

	context.JSON(http.StatusOK, res)
}

// @Tags 登录接口
// @Summary 登录
// @Description login
// @Accept json
// @Produce json
// @Param username query string true "用户名"
// @Param password query string false "密码"
// @Success 200 {string} json "{"code": 200, "data":"{"name":"username","password":"password"}","msg":"OK"}"
// @Router /login [get]
func login(context *gin.Context) {
	userName := context.Query("name")
	pwd := context.Query("pwd")

	fmt.Println(userName, pwd)

	res := Response{}
	res.Code = http.StatusOK
	res.Msg = "登陆成功"
	res.Data = "OK"

	context.JSON(http.StatusOK, res)
}

gin框架cookie

go 复制代码
package main

import (
	"encoding/hex"
	"fmt"
	"github.com/gin-gonic/gin"
	"net/http"
)

var cookieName string
var cookieValue string

func main() {
	r := gin.Default()

	r.Use(cookieAuth())

	r.GET("/cookie", func(context *gin.Context) {
		name := context.Query("name")

		if len(name) <= 0 {
			context.JSON(http.StatusOK, "数据错误")
			return
		}

		cookieName = "cookie_" + name
		cookieValue = hex.EncodeToString([]byte(cookieName + "value"))
		val, _ := context.Cookie(cookieName)

		if val == "" {
			context.String(http.StatusOK, "Cookie已经下发,下次登录有效", cookieName)
			return
		}
		context.String(http.StatusOK, "验证成功,cookie值为:%s", val)
	})

	r.Run(":9090")
}

func cookieAuth() gin.HandlerFunc {
	return func(context *gin.Context) {
		val, _ := context.Cookie(cookieName)

		if val == "" {
			context.SetCookie(cookieName, cookieValue, 3600, "/", "localhost", true, true)
			fmt.Println("cookie已经保存完成!")
		}
	}
}

gin框架session

go 复制代码
package main

import (
	"net/http"

	"github.com/gin-contrib/sessions"
	"github.com/gin-contrib/sessions/cookie"
	"github.com/gin-gonic/gin"
)

func main() {
	r := gin.Default()

	// 加入 session 中间件
	store := cookie.NewStore([]byte("session_secret")) // 创建基于cookie的session存储
	r.Use(sessions.Sessions("mySession", store))       // 使用session中间件,并指定session名称和存储方式

	r.GET("/session", func(context *gin.Context) {
		name := context.Query("name")
		if len(name) <= 0 {
			context.JSON(http.StatusOK, "数据错误")
			return
		}

		sessionName := "session_" + name        // 构造session名称
		sessionValue := "session_value_" + name // 构造session值

		session := sessions.Default(context) // 获取默认的session实例
		sessionData := session.Get(sessionName)

		if sessionData != sessionValue { // 如果session中不存在对应值,则为首次访问
			session.Set(sessionName, sessionValue) // 设置 session
			session.Save()                         // 保存 session

			context.JSON(http.StatusOK, "首次访问,session已保存:"+sessionValue)
			return
		}
		context.JSON(http.StatusOK, "访问成功,您的session是:"+sessionData.(string))
	})

	r.Run(":9090") // 启动HTTP服务器,监听9090端口
}

gin框架Https

go 复制代码
package main

import (
	"github.com/gin-gonic/gin"
	"github.com/unrolled/secure"
	"net/http"
)

// HttpRes 结构体用于定义HTTP响应格式
type HttpRes struct {
	Code   int    `json:"code"`   // 响应状态码
	Result string `json:"result"` // 响应结果消息
}

func main() {
	r := gin.Default() // 创建默认的gin路由引擎

	// 使用HTTPS处理程序中间件
	r.Use(httpsHandler())

	// 定义GET路由"/https_test"
	r.GET("/https_test", func(context *gin.Context) {
		// 返回JSON格式的成功消息
		context.JSON(http.StatusOK, HttpRes{
			Code:   http.StatusOK,
			Result: "测试成功",
		})
	})

	path := "D:/2-golang/CA/"                       // 证书路径
	r.RunTLS(":9090", path+"ca.crt", path+"ca.key") // 使用TLS在9090端口运行服务器
}

// httpsHandler 返回一个处理HTTPS请求的中间件函数
func httpsHandler() gin.HandlerFunc {
	return func(context *gin.Context) {
		// 创建secure中间件实例
		secureMiddleware := secure.New(secure.Options{
			SSLRedirect:          true, // 强制SSL重定向
			STSSeconds:           1536000,
			STSIncludeSubdomains: true,
			STSPreload:           true,
			FrameDeny:            true,
			ContentTypeNosniff:   true,
			BrowserXssFilter:     true,
		})
		// 处理HTTPS请求
		err := secureMiddleware.Process(context.Writer, context.Request)
		if err != nil {
			// 如果出现错误,返回数据不安全的响应
			context.AbortWithStatusJSON(http.StatusBadRequest, "数据不安全")
			return
		}
		if status := context.Writer.Status(); status > 300 && status < 399 {
			// 如果响应状态码是重定向类型,则终止请求
			context.Abort()
			return
		}
		context.Next() // 继续处理下一个中间件或路由处理函数
	}
}
相关推荐
奇遇少年20 分钟前
HTTPS基础
网络协议·http·https
才艺のblog1 小时前
127还是localhost....?
javascript·https·浏览器特性
战神刘玉栋19 小时前
《企业实战分享 · 常用运维中间件》
运维·spring cloud·中间件
LightOfNight1 天前
【后端面试题】【中间件】【NoSQL】ElasticSearch的优化方案1(分页查询、刷新间隔、批量提交)
数据库·redis·后端·elasticsearch·缓存·中间件·nosql
xintaiideas1 天前
开发中间件的底层原理通常涉及以下几个关键方面:
中间件
CooperYXQ1 天前
这一次终于理解了三次握手四次挥手
tcp/ip·https
Jamesvalley1 天前
【Gin】项目搭建 一
gin
LightOfNight1 天前
【后端面试题】【中间件】【NoSQL】ElasticSearch的优化方案2(减少字段、冷热分离、参数优化)
分布式·后端·elasticsearch·中间件·架构·nosql
我就是菜鸡12291 天前
【微服务网关——https与http2代理实现】
微服务·架构·https
LightOfNight1 天前
【后端面试题】【中间件】【NoSQL】MongoDB的配置服务器、复制机制、写入语义和面试准备
分布式·后端·mongodb·中间件·面试·架构·nosql